Merge "riscv64: enable V." into main
diff --git a/README.md b/README.md
index 2d8f0af..22daa95 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,6 @@
 [bug tracker](https://issuetracker.google.com/issues/new?component=381517) or
 or write us at android-building@googlegroups.com .
 
-For Googlers, see our [internal documentation](http://go/soong).
-
 ## Android.bp file format
 
 By design, Android.bp files are very simple.  There are no conditionals or
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index 6927765..d2ddfdf 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -14,6 +14,7 @@
         "soong-bazel",
         "soong-android",
         "soong-java",
+        "soong-rust",
     ],
     srcs: [
         "aconfig_declarations.go",
@@ -24,6 +25,7 @@
         "init.go",
         "java_aconfig_library.go",
         "testing.go",
+        "rust_aconfig_library.go",
     ],
     testSrcs: [
         "aconfig_declarations_test.go",
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 565d185..5cdf5b6 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -17,8 +17,9 @@
 import (
 	"android/soong/android"
 	"fmt"
-	"github.com/google/blueprint"
 	"strings"
+
+	"github.com/google/blueprint"
 )
 
 type DeclarationsModule struct {
@@ -96,6 +97,15 @@
 	return sb.String()
 }
 
+func optionalVariable(prefix string, value string) string {
+	var sb strings.Builder
+	if value != "" {
+		sb.WriteString(prefix)
+		sb.WriteString(value)
+	}
+	return sb.String()
+}
+
 // Provider published by aconfig_value_set
 type declarationsProviderData struct {
 	Package          string
@@ -106,32 +116,40 @@
 
 func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag
+	valuesFiles := make([]android.Path, 0)
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		if !ctx.OtherModuleHasProvider(dep, valueSetProviderKey) {
 			// Other modules get injected as dependencies too, for example the license modules
 			return
 		}
 		depData := ctx.OtherModuleProvider(dep, valueSetProviderKey).(valueSetProviderData)
-		valuesFiles, ok := depData.AvailablePackages[module.properties.Package]
+		paths, ok := depData.AvailablePackages[module.properties.Package]
 		if ok {
-			for _, path := range valuesFiles {
+			valuesFiles = append(valuesFiles, paths...)
+			for _, path := range paths {
 				module.properties.Values = append(module.properties.Values, path.String())
 			}
 		}
 	})
 
 	// Intermediate format
-	inputFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+	declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs)
 	intermediatePath := android.PathForModuleOut(ctx, "intermediate.pb")
+	defaultPermission := ctx.Config().ReleaseAconfigFlagDefaultPermission()
+	inputFiles := make([]android.Path, len(declarationFiles))
+	copy(inputFiles, declarationFiles)
+	inputFiles = append(inputFiles, valuesFiles...)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        aconfigRule,
 		Output:      intermediatePath,
+		Inputs:      inputFiles,
 		Description: "aconfig_declarations",
 		Args: map[string]string{
-			"release_version": ctx.Config().ReleaseVersion(),
-			"package":         module.properties.Package,
-			"declarations":    android.JoinPathsWithPrefix(inputFiles, "--declarations "),
-			"values":          joinAndPrefix(" --values ", module.properties.Values),
+			"release_version":    ctx.Config().ReleaseVersion(),
+			"package":            module.properties.Package,
+			"declarations":       android.JoinPathsWithPrefix(declarationFiles, "--declarations "),
+			"values":             joinAndPrefix(" --values ", module.properties.Values),
+			"default-permission": optionalVariable(" --default-permission ", defaultPermission),
 		},
 	})
 
diff --git a/aconfig/init.go b/aconfig/init.go
index 3ed5faf..797388d 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 )
 
@@ -29,14 +30,15 @@
 				` --package ${package}` +
 				` ${declarations}` +
 				` ${values}` +
+				` ${default-permission}` +
 				` --cache ${out}.tmp` +
-				` && ( if cmp -s ${out}.tmp ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
+				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
 			//				` --build-id ${release_version}` +
 			CommandDeps: []string{
 				"${aconfig}",
 			},
 			Restat: true,
-		}, "release_version", "package", "declarations", "values")
+		}, "release_version", "package", "declarations", "values", "default-permission")
 
 	// For java_aconfig_library: Generate java file
 	javaRule = pctx.AndroidStaticRule("java_aconfig_library",
@@ -44,6 +46,7 @@
 			Command: `rm -rf ${out}.tmp` +
 				` && mkdir -p ${out}.tmp` +
 				` && ${aconfig} create-java-lib` +
+				`    --mode ${mode}` +
 				`    --cache ${in}` +
 				`    --out ${out}.tmp` +
 				` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` +
@@ -53,7 +56,7 @@
 				"$soong_zip",
 			},
 			Restat: true,
-		})
+		}, "mode")
 
 	// For java_aconfig_library: Generate java file
 	cppRule = pctx.AndroidStaticRule("cc_aconfig_library",
@@ -69,6 +72,20 @@
 			},
 		}, "gendir")
 
+	rustRule = pctx.AndroidStaticRule("rust_aconfig_library",
+		blueprint.RuleParams{
+			Command: `rm -rf ${gendir}` +
+				` && mkdir -p ${gendir}` +
+				` && ${aconfig} create-rust-lib` +
+				`    --mode ${mode}` +
+				`    --cache ${in}` +
+				`    --out ${gendir}`,
+			CommandDeps: []string{
+				"$aconfig",
+				"$soong_zip",
+			},
+		}, "gendir", "mode")
+
 	// For all_aconfig_declarations
 	allDeclarationsRule = pctx.AndroidStaticRule("all_aconfig_declarations_dump",
 		blueprint.RuleParams{
@@ -91,5 +108,6 @@
 	ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory)
 	ctx.RegisterModuleType("cc_aconfig_library", CcAconfigLibraryFactory)
 	ctx.RegisterModuleType("java_aconfig_library", JavaDeclarationsLibraryFactory)
+	ctx.RegisterModuleType("rust_aconfig_library", RustAconfigLibraryFactory)
 	ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory)
 }
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index 53b2b10..4db0ef7 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -30,6 +30,9 @@
 type JavaAconfigDeclarationsLibraryProperties struct {
 	// name of the aconfig_declarations module to generate a library for
 	Aconfig_declarations string
+
+	// whether to generate test mode version of the library
+	Test bool
 }
 
 type JavaAconfigDeclarationsLibraryCallbacks struct {
@@ -49,6 +52,9 @@
 	} else {
 		ctx.AddDependency(ctx.Module(), declarationsTag, declarations)
 	}
+
+	// Add aconfig-annotations-lib as a dependency for the optimization / code stripping annotations
+	module.AddSharedLibrary("aconfig-annotations-lib")
 }
 
 func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) android.Path {
@@ -61,11 +67,20 @@
 
 	// Generate the action to build the srcjar
 	srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar")
+	var mode string
+	if callbacks.properties.Test {
+		mode = "test"
+	} else {
+		mode = "production"
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        javaRule,
 		Input:       declarations.IntermediatePath,
 		Output:      srcJarPath,
 		Description: "aconfig.srcjar",
+		Args: map[string]string{
+			"mode": mode,
+		},
 	})
 
 	// Tell the java module about the .aconfig files, so they can be propagated up the dependency chain.
diff --git a/aconfig/java_aconfig_library_test.go b/aconfig/java_aconfig_library_test.go
index 1808290..af50848 100644
--- a/aconfig/java_aconfig_library_test.go
+++ b/aconfig/java_aconfig_library_test.go
@@ -15,6 +15,7 @@
 package aconfig
 
 import (
+	"fmt"
 	"strings"
 	"testing"
 
@@ -152,3 +153,39 @@
 
 	runJavaAndroidMkTest(t, bp)
 }
+
+func testCodegenMode(t *testing.T, bpMode string, ruleMode string) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		java.PrepareForTestWithJavaDefaultModules).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			java_aconfig_library {
+				name: "my_java_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+				%s
+			}
+		`, bpMode))
+
+	module := result.ModuleForTests("my_java_aconfig_library", "android_common")
+	rule := module.Rule("java_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode)
+}
+
+func TestDefaultProdMode(t *testing.T) {
+	testCodegenMode(t, "", "production")
+}
+
+func TestProdMode(t *testing.T) {
+	testCodegenMode(t, "test: false,", "production")
+}
+
+func TestTestMode(t *testing.T) {
+	testCodegenMode(t, "test: true,", "test")
+}
diff --git a/aconfig/rust_aconfig_library.go b/aconfig/rust_aconfig_library.go
new file mode 100644
index 0000000..de41776
--- /dev/null
+++ b/aconfig/rust_aconfig_library.go
@@ -0,0 +1,89 @@
+package aconfig
+
+import (
+	"android/soong/android"
+	"android/soong/rust"
+	"fmt"
+
+	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
+)
+
+type rustDeclarationsTagType struct {
+	blueprint.BaseDependencyTag
+}
+
+var rustDeclarationsTag = rustDeclarationsTagType{}
+
+type RustAconfigLibraryProperties struct {
+	// name of the aconfig_declarations module to generate a library for
+	Aconfig_declarations string
+	Test                 *bool
+}
+
+type aconfigDecorator struct {
+	*rust.BaseSourceProvider
+
+	Properties RustAconfigLibraryProperties
+}
+
+func NewRustAconfigLibrary(hod android.HostOrDeviceSupported) (*rust.Module, *aconfigDecorator) {
+	aconfig := &aconfigDecorator{
+		BaseSourceProvider: rust.NewSourceProvider(),
+		Properties:         RustAconfigLibraryProperties{},
+	}
+
+	module := rust.NewSourceProviderModule(android.HostAndDeviceSupported, aconfig, false, false)
+	return module, aconfig
+}
+
+// rust_aconfig_library generates aconfig rust code from the provided aconfig declaration. This module type will
+// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// properties of other modules.
+func RustAconfigLibraryFactory() android.Module {
+	module, _ := NewRustAconfigLibrary(android.HostAndDeviceSupported)
+	return module.Init()
+}
+
+func (a *aconfigDecorator) SourceProviderProps() []interface{} {
+	return append(a.BaseSourceProvider.SourceProviderProps(), &a.Properties)
+}
+
+func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
+	generatedDir := android.PathForModuleGen(ctx)
+	generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs")
+
+	declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag)
+
+	if len(declarationsModules) != 1 {
+		panic(fmt.Errorf("Exactly one aconfig_declarations property required"))
+	}
+	declarations := ctx.OtherModuleProvider(declarationsModules[0], declarationsProviderKey).(declarationsProviderData)
+
+	mode := "production"
+	if proptools.Bool(a.Properties.Test) {
+		mode = "test"
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:  rustRule,
+		Input: declarations.IntermediatePath,
+		Outputs: []android.WritablePath{
+			generatedSource,
+		},
+		Description: "rust_aconfig_library",
+		Args: map[string]string{
+			"gendir": generatedDir.String(),
+			"mode":   mode,
+		},
+	})
+	a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource}
+	return generatedSource
+}
+
+func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps {
+	deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps)
+	deps.Rustlibs = append(deps.Rustlibs, "libflags_rust")
+	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
new file mode 100644
index 0000000..17385c3
--- /dev/null
+++ b/aconfig/rust_aconfig_library_test.go
@@ -0,0 +1,60 @@
+package aconfig
+
+import (
+	"android/soong/android"
+	"android/soong/rust"
+	"fmt"
+	"testing"
+)
+
+func TestRustAconfigLibrary(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithAconfigBuildComponents,
+		rust.PrepareForTestWithRustIncludeVndk,
+		android.PrepareForTestWithArchMutator,
+		android.PrepareForTestWithDefaults,
+		android.PrepareForTestWithPrebuilts,
+	).
+		ExtendWithErrorHandler(android.FixtureExpectsNoErrors).
+		RunTestWithBp(t, fmt.Sprintf(`
+			rust_library {
+				name: "libflags_rust", // test mock
+				crate_name: "flags_rust",
+				srcs: ["lib.rs"],
+			}
+			aconfig_declarations {
+				name: "my_aconfig_declarations",
+				package: "com.example.package",
+				srcs: ["foo.aconfig"],
+			}
+
+			rust_aconfig_library {
+				name: "libmy_rust_aconfig_library",
+				crate_name: "my_rust_aconfig_library",
+				aconfig_declarations: "my_aconfig_declarations",
+			}
+		`))
+
+	sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source")
+	rule := sourceVariant.Rule("rust_aconfig_library")
+	android.AssertStringEquals(t, "rule must contain production mode", rule.Args["mode"], "production")
+
+	dylibVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib")
+	rlibRlibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std")
+	rlibDylibStdVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std")
+
+	variants := []android.TestingModule{
+		dylibVariant,
+		rlibDylibStdVariant,
+		rlibRlibStdVariant,
+	}
+
+	for _, variant := range variants {
+		android.AssertStringEquals(
+			t,
+			"dylib variant builds from generated rust code",
+			"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
+			variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
+		)
+	}
+}
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 8ccef8d..76ae2d0 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -121,6 +121,7 @@
 		"development/sdk":                             Bp2BuildDefaultTrueRecursively,
 
 		"external/aac":                           Bp2BuildDefaultTrueRecursively,
+		"external/abseil-cpp":                    Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines":        Bp2BuildDefaultTrueRecursively,
 		"external/auto":                          Bp2BuildDefaultTrue,
 		"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
@@ -144,6 +145,7 @@
 		"external/flatbuffers":                   Bp2BuildDefaultTrueRecursively,
 		"external/fmtlib":                        Bp2BuildDefaultTrueRecursively,
 		"external/fsverity-utils":                Bp2BuildDefaultTrueRecursively,
+		"external/gflags":                        Bp2BuildDefaultTrueRecursively,
 		"external/google-benchmark":              Bp2BuildDefaultTrueRecursively,
 		"external/googletest":                    Bp2BuildDefaultTrueRecursively,
 		"external/guava":                         Bp2BuildDefaultTrueRecursively,
@@ -176,6 +178,7 @@
 		"external/libjpeg-turbo":                 Bp2BuildDefaultTrueRecursively,
 		"external/libmpeg2":                      Bp2BuildDefaultTrueRecursively,
 		"external/libpng":                        Bp2BuildDefaultTrueRecursively,
+		"external/libphonenumber":                Bp2BuildDefaultTrueRecursively,
 		"external/libvpx":                        Bp2BuildDefaultTrueRecursively,
 		"external/libyuv":                        Bp2BuildDefaultTrueRecursively,
 		"external/lz4/lib":                       Bp2BuildDefaultTrue,
@@ -189,7 +192,11 @@
 		"external/ow2-asm":                       Bp2BuildDefaultTrueRecursively,
 		"external/pcre":                          Bp2BuildDefaultTrueRecursively,
 		"external/protobuf":                      Bp2BuildDefaultTrueRecursively,
+		"external/python/pyyaml/lib/yaml":        Bp2BuildDefaultTrueRecursively,
 		"external/python/six":                    Bp2BuildDefaultTrueRecursively,
+		"external/python/jinja/src":              Bp2BuildDefaultTrueRecursively,
+		"external/python/markupsafe/src":         Bp2BuildDefaultTrueRecursively,
+		"external/python/setuptools":             Bp2BuildDefaultTrueRecursively,
 		"external/rappor":                        Bp2BuildDefaultTrueRecursively,
 		"external/scudo":                         Bp2BuildDefaultTrueRecursively,
 		"external/selinux/checkpolicy":           Bp2BuildDefaultTrueRecursively,
@@ -215,6 +222,7 @@
 		"frameworks/av/media/module/foundation":              Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/media/module/minijail":                Bp2BuildDefaultTrueRecursively,
 		"frameworks/av/services/minijail":                    Bp2BuildDefaultTrueRecursively,
+		"frameworks/base/core/java":                          Bp2BuildDefaultTrue,
 		"frameworks/base/libs/androidfw":                     Bp2BuildDefaultTrue,
 		"frameworks/base/libs/services":                      Bp2BuildDefaultTrue,
 		"frameworks/base/media/tests/MediaDump":              Bp2BuildDefaultTrue,
@@ -222,19 +230,22 @@
 		"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/streaming_proto":              Bp2BuildDefaultTrueRecursively,
 		"frameworks/hardware/interfaces/stats/aidl":          Bp2BuildDefaultTrue,
 		"frameworks/libs/modules-utils/build":                Bp2BuildDefaultTrueRecursively,
-		"frameworks/libs/net/common/native":                  Bp2BuildDefaultTrueRecursively,
+		"frameworks/libs/net/common/native":                  Bp2BuildDefaultTrueRecursively, // TODO(b/296014682): Remove this path
 		"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,
@@ -249,6 +260,7 @@
 		"hardware/interfaces/audio/aidl/common":                   Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl/default":                  Bp2BuildDefaultTrue,
 		"hardware/interfaces/audio/aidl/sounddose":                Bp2BuildDefaultTrue,
+		"hardware/interfaces/camera/metadata/aidl":                Bp2BuildDefaultTrueRecursively,
 		"hardware/interfaces/common/aidl":                         Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/fmq/aidl":                     Bp2BuildDefaultTrue,
 		"hardware/interfaces/common/support":                      Bp2BuildDefaultTrue,
@@ -277,13 +289,9 @@
 		"hardware/interfaces/health/2.1":                          Bp2BuildDefaultTrue,
 		"hardware/interfaces/health/aidl":                         Bp2BuildDefaultTrue,
 		"hardware/interfaces/health/utils":                        Bp2BuildDefaultTrueRecursively,
-		"hardware/interfaces/media/1.0":                           Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/bufferpool":                    Bp2BuildDefaultTrueRecursively,
+		"hardware/interfaces/media":                               Bp2BuildDefaultTrueRecursively,
 		"hardware/interfaces/media/bufferpool/aidl/default/tests": Bp2BuildDefaultFalseRecursively,
-		"hardware/interfaces/media/c2/1.0":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.1":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/c2/1.2":                        Bp2BuildDefaultTrue,
-		"hardware/interfaces/media/omx/1.0":                       Bp2BuildDefaultTrue,
+		"hardware/interfaces/media/omx/1.0/vts":                   Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks":                      Bp2BuildDefaultTrueRecursively,
 		"hardware/interfaces/neuralnetworks/aidl/vts":             Bp2BuildDefaultFalseRecursively,
 		"hardware/interfaces/neuralnetworks/1.0/vts":              Bp2BuildDefaultFalseRecursively,
@@ -303,12 +311,14 @@
 		"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,
@@ -331,6 +341,7 @@
 		"prebuilts/sdk/current/support":                    Bp2BuildDefaultTrue,
 		"prebuilts/tools":                                  Bp2BuildDefaultTrue,
 		"prebuilts/tools/common/m2":                        Bp2BuildDefaultTrue,
+		"prebuilts/r8":                                     Bp2BuildDefaultTrueRecursively,
 
 		"sdk/dumpeventlog":  Bp2BuildDefaultTrue,
 		"sdk/eventanalyzer": Bp2BuildDefaultTrue,
@@ -361,6 +372,7 @@
 		"system/core/mkbootfs":                                   Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoparser":     Bp2BuildDefaultTrueRecursively,
 		"system/core/property_service/libpropertyinfoserializer": Bp2BuildDefaultTrueRecursively,
+		"system/core/trusty/libtrusty":                           Bp2BuildDefaultTrue,
 		"system/extras/f2fs_utils":                               Bp2BuildDefaultTrueRecursively,
 		"system/extras/toolchain-extras":                         Bp2BuildDefaultTrue,
 		"system/extras/verity":                                   Bp2BuildDefaultTrueRecursively,
@@ -369,6 +381,7 @@
 		"system/libartpalette":                                   Bp2BuildDefaultTrueRecursively,
 		"system/libbase":                                         Bp2BuildDefaultTrueRecursively,
 		"system/libfmq":                                          Bp2BuildDefaultTrue,
+		"system/libhidl":                                         Bp2BuildDefaultTrue,
 		"system/libhidl/libhidlmemory":                           Bp2BuildDefaultTrue,
 		"system/libhidl/transport":                               Bp2BuildDefaultTrue,
 		"system/libhidl/transport/allocator/1.0":                 Bp2BuildDefaultTrue,
@@ -390,6 +403,7 @@
 		"system/media/audio":                                     Bp2BuildDefaultTrueRecursively,
 		"system/media/alsa_utils":                                Bp2BuildDefaultTrueRecursively,
 		"system/media/audio_utils":                               Bp2BuildDefaultTrueRecursively,
+		"system/media/camera":                                    Bp2BuildDefaultTrueRecursively,
 		"system/memory/libion":                                   Bp2BuildDefaultTrueRecursively,
 		"system/memory/libmemunreachable":                        Bp2BuildDefaultTrueRecursively,
 		"system/sepolicy/apex":                                   Bp2BuildDefaultTrueRecursively,
@@ -402,6 +416,7 @@
 		"system/tools/aidl/build/tests_bp2build":                 Bp2BuildDefaultTrue,
 		"system/tools/aidl/metadata":                             Bp2BuildDefaultTrue,
 		"system/tools/hidl/metadata":                             Bp2BuildDefaultTrue,
+		"system/tools/hidl/utils":                                Bp2BuildDefaultTrue,
 		"system/tools/mkbootimg":                                 Bp2BuildDefaultTrueRecursively,
 		"system/tools/sysprop":                                   Bp2BuildDefaultTrue,
 		"system/tools/xsdc/utils":                                Bp2BuildDefaultTrueRecursively,
@@ -410,7 +425,7 @@
 		"tools/apifinder":                            Bp2BuildDefaultTrue,
 		"tools/apksig":                               Bp2BuildDefaultTrue,
 		"tools/external_updater":                     Bp2BuildDefaultTrueRecursively,
-		"tools/metalava":                             Bp2BuildDefaultTrue,
+		"tools/metalava":                             Bp2BuildDefaultTrueRecursively,
 		"tools/platform-compat/java/android/compat":  Bp2BuildDefaultTrueRecursively,
 		"tools/tradefederation/prebuilts/filegroups": Bp2BuildDefaultTrueRecursively,
 	}
@@ -431,9 +446,12 @@
 		// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
 		// e.g. ERROR: Analysis of target '@soong_injection//mixed_builds:buildroot' failed
 		"external/bazelbuild-rules_android":/* recursive = */ true,
+		"external/bazelbuild-rules_cc":/* recursive = */ true,
 		"external/bazelbuild-rules_java":/* recursive = */ true,
 		"external/bazelbuild-rules_license":/* recursive = */ true,
 		"external/bazelbuild-rules_go":/* recursive = */ true,
+		"external/bazelbuild-rules_python":/* recursive = */ true,
+		"external/bazelbuild-rules_rust":/* recursive = */ true,
 		"external/bazelbuild-kotlin-rules":/* recursive = */ true,
 		"external/bazel-skylib":/* recursive = */ true,
 		"external/protobuf":/* recursive = */ false,
@@ -461,6 +479,7 @@
 		"prebuilts/sdk/tools":/* recursive = */ false,
 		"prebuilts/r8":/* recursive = */ false,
 		"prebuilts/runtime":/* recursive = */ false,
+		"prebuilts/rust":/* recursive = */ true,
 
 		// not recursive due to conflicting workspace paths in tools/atest/bazel/rules
 		"tools/asuite/atest":/* recursive = */ false,
@@ -474,6 +493,80 @@
 	}
 
 	Bp2buildModuleAlwaysConvertList = []string{
+		// aconfig
+		"libonce_cell",
+		"libanyhow",
+		"libunicode_segmentation",
+		"libmemchr",
+		"libbitflags-1.3.2",
+		"libryu",
+		"libitoa",
+		"libos_str_bytes",
+		"libheck",
+		"libclap_lex",
+		"libsyn",
+		"libquote",
+		"libunicode_ident",
+		"libproc_macro2",
+		"libthiserror_impl",
+		"libserde_derive",
+		"libclap_derive",
+		"libthiserror",
+		"libserde",
+		"libclap",
+		"libbytes",
+		"libprotobuf_support",
+		"libtinytemplate",
+		"libserde_json",
+		"libprotobuf",
+
+		"protoc-gen-rust",
+		"libprotobuf_codegen",
+		"libprotobuf_parse",
+		"libregex",
+		"libtempfile",
+		"libwhich",
+		"libregex_syntax",
+		"libfastrand",
+		"libeither",
+		"libaho_corasick",
+		"liblibc",
+		"libcfg_if",
+		"liblog_rust",
+		"libgetrandom",
+		"libremove_dir_all",
+		"libahash",
+		"libhashbrown",
+		"libindexmap",
+		"libaconfig_protos",
+		"libpaste",
+		"aconfig",
+
+		// ext
+		"tagsoup",
+
+		// framework-res
+		"remote-color-resources-compile-public",
+		"remote-color-resources-compile-colors",
+
+		// framework-minus-apex
+		"android.mime.types.minimized",
+		"debian.mime.types.minimized",
+		"framework-javastream-protos",
+		"libview-inspector-annotation-processor",
+
+		// services
+		"apache-commons-math",
+		"cbor-java",
+		"icu4j_calendar_astronomer",
+		"json",
+		"remote-color-resources-compile-public",
+		"statslog-art-java-gen",
+
+		"AndroidCommonLint",
+		"ImmutabilityAnnotation",
+		"ImmutabilityAnnotationProcessorHostLibrary",
+
 		"libidmap2_policies",
 		"libSurfaceFlingerProp",
 		"toolbox_input_labels",
@@ -501,10 +594,6 @@
 		"libandroid_runtime_lazy",
 		"libandroid_runtime_vm_headers",
 		"libaudioclient_aidl_conversion_util",
-		"libbinder",
-		"libbinder_device_interface_sources",
-		"libbinder_aidl",
-		"libbinder_headers",
 		"libbinder_headers_platform_shared",
 		"libbinderthreadstateutils",
 		"libbluetooth-types-header",
@@ -537,9 +626,6 @@
 		"libtextclassifier_hash_static",
 		"libtflite_kernel_utils",
 		"libtinyxml2",
-		"libui",
-		"libui-types",
-		"libui_headers",
 		"libvorbisidec",
 		"media_ndk_headers",
 		"media_plugin_headers",
@@ -547,8 +633,6 @@
 		"mediaswcodec.xml",
 		"neuralnetworks_types",
 		"libneuralnetworks_common",
-		// packagemanager_aidl_interface is created implicitly in packagemanager_aidl module
-		"packagemanager_aidl_interface",
 		"philox_random",
 		"philox_random_headers",
 		"server_configurable_flags",
@@ -590,9 +674,6 @@
 		//external/fec
 		"libfec_rs",
 
-		//frameworks/base/core/java
-		"IDropBoxManagerService_aidl",
-
 		//system/extras/ext4_utils
 		"libext4_utils",
 		"mke2fs_conf",
@@ -613,10 +694,6 @@
 		"car-ui-androidx-lifecycle-common-nodeps",
 		"car-ui-androidx-constraintlayout-solver-nodeps",
 
-		//system/libhidl
-		"libhidlbase", // needed by cc_hidl_library
-		"libhidl_gtest_helper",
-
 		//frameworks/native/libs/input
 		"inputconstants_aidl",
 
@@ -625,14 +702,12 @@
 
 		"libusb",
 
-		// needed by liblogd
-		"ILogcatManagerService_aidl",
-		"libincremental_aidl-cpp",
-		"incremental_aidl",
-
 		//frameworks/native/cmds/cmd
 		"libcmd",
 
+		//system/chre
+		"chre_api",
+
 		//system/core/fs_mgr/libdm
 		"libdm",
 
@@ -813,6 +888,16 @@
 		"chre_flatbuffers",
 		"event_logger",
 		"hal_unit_tests",
+
+		"merge_annotation_zips_test",
+
+		// bouncycastle dep
+		"platform-test-annotations",
+
+		// java_resources with multiple resource_dirs
+		"emma",
+
+		"modules-utils-preconditions-srcs",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -836,6 +921,24 @@
 	// 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",
+		"libbssl_ffi_nostd",
+		"pull_rust",
+		"libstatslog_rust",
+		"libstatslog_rust_header",
+		"libflatbuffers",
+		"liblog_event_list",
+		"libminijail_rust",
+		"libminijail_sys",
+		"libfsverity_rs",
+		"libtombstoned_client_rust",
+
+		// TODO(b/263326760): Failed already.
+		"minijail_compiler_unittest",
+		"minijail_parser_unittest",
+
 		// Depends on unconverted libandroid, libgui
 		"dvr_buffer_queue-test",
 		"dvr_display-test",
@@ -864,8 +967,9 @@
 		"apexer_test", "apexer_test_host_tools", "host_apex_verifier",
 
 		// java bugs
-		"libbase_ndk",  // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
-		"bouncycastle", // TODO(b/274474005): Need support for custom system_modules.
+		"libbase_ndk",           // TODO(b/186826477): fails to link libctscamera2_jni for device (required for CtsCameraTestCases)
+		"bouncycastle",          // TODO(b/274474005): Need support for custom system_modules.
+		"bouncycastle-test-lib", // TODO(b/274474005): Reverse dependency of bouncycastle
 
 		// genrule incompatibilities
 		"brotli-fuzzer-corpus",                                       // TODO(b/202015218): outputs are in location incompatible with bazel genrule handling.
@@ -882,7 +986,6 @@
 		"conscrypt-for-host",               // TODO(b/210751803), we don't handle path property for filegroups
 		"host-libprotobuf-java-full",       // TODO(b/210751803), we don't handle path property for filegroups
 		"libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups
-		"libprotobuf-java-full",            // TODO(b/210751803), we don't handle path property for filegroups
 		"libprotobuf-java-util-full",       // TODO(b/210751803), we don't handle path property for filegroups
 
 		// go deps:
@@ -895,15 +998,15 @@
 		"libtombstoned_client_rust_bridge_code", "libtombstoned_client_wrapper", // rust conversions are not supported
 
 		// unconverted deps
-		"apexer_with_DCLA_preprocessing_test",                        // depends on unconverted modules: apexer_test_host_tools, com.android.example.apex
+		"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
-		"CarHTMLViewer",                                              // depends on unconverted modules android.car-stubs, car-ui-lib
 		"com.android.runtime",                                        // depends on unconverted modules: bionic-linker-config, linkerconfig
 		"currysrc",                                                   // depends on unconverted modules: currysrc_org.eclipse, guavalib, jopt-simple-4.9
 		"dex2oat-script",                                             // depends on unconverted modules: dex2oat
@@ -913,21 +1016,24 @@
 		"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
-		"libfastdeploy_host",                                      // depends on unconverted modules: libandroidfw, libusb, AdbWinApi
 		"libgmock_main_ndk",                                       // depends on unconverted modules: libgtest_ndk_c++
 		"libgmock_ndk",                                            // depends on unconverted modules: libgtest_ndk_c++
 		"libnativehelper_lazy_mts_jni", "libnativehelper_mts_jni", // depends on unconverted modules: libnativetesthelper_jni, libgmock_ndk
 		"libnativetesthelper_jni",   // depends on unconverted modules: libgtest_ndk_c++
+		"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_*
@@ -977,8 +1083,6 @@
 		"svcenc", "svcdec",
 
 		// Failing host cc_tests
-		"libprocinfo_test",
-		"ziparchive-tests",
 		"gtest_isolated_tests",
 		"libunwindstack_unit_test",
 		"power_tests", // failing test on server, but not on host
@@ -997,7 +1101,7 @@
 		"libnativebridge6-test-case",
 		"libnativebridge6prezygotefork",
 
-		"libandroidfw_tests", "aapt2_tests", // failing due to data path issues
+		"libandroidfw_tests", // failing due to data path issues
 
 		// error: overriding commands for target
 		// `out/host/linux-x86/nativetest64/gmock_tests/gmock_tests__cc_runner_test',
@@ -1055,6 +1159,7 @@
 		"ion-unit-tests",
 		"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
@@ -1084,7 +1189,6 @@
 		"memunreachable_binder_test", // depends on unconverted modules: libbinder
 		"memunreachable_test",
 		"metadata_tests",
-		"minijail0_cli_unittest_gtest",
 		"mpeg2dec",
 		"mvcdec",
 		"ns_hidden_child_helper",
@@ -1096,14 +1200,12 @@
 		"rappor-tests", // depends on unconverted modules: jsr305, guava
 		"scudo_unit_tests",
 		"stats-log-api-gen-test", // depends on unconverted modules: libstats_proto_host
-		"syscall_filter_unittest_gtest",
 		"thread_exit_cb_helper",
 		"tls_properties_helper",
 		"ulp",
 		"vec_test",
 		"yuvconstants",
 		"yuvconvert",
-		"zipalign_tests",
 
 		// cc_test_library
 		"clang_diagnostic_tests",
@@ -1498,6 +1600,7 @@
 		"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
@@ -1511,73 +1614,31 @@
 		"libart_generated_headers",
 		"libart-runtime-gtest",
 		"libartd-runtime-gtest",
-	}
+		"libart-unstripped",
 
-	MixedBuildsDisabledList = []string{
-		"libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
+		// depends on libart-unstripped and new module type llvm_prebuilt_build_tool
+		"check_cfi",
 
-		"art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
+		// depends on unconverted module tradefed
+		"HelloWorldPerformanceTest",
 
-		"libbrotli",               // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
-		"minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
+		// 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",
 
-		"cap_names.h",                                  // TODO(b/204913827) runfiles need to be handled in mixed builds
-		"libcap",                                       // TODO(b/204913827) runfiles need to be handled in mixed builds
-		"libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
+		// Depends on the module defined in the directory not bp2build default allowed
+		"ota_from_raw_img",
 
-		// Depends on libprotobuf-cpp-*
-		"libadb_pairing_connection",
-		"libadb_pairing_connection_static",
-		"libadb_pairing_server", "libadb_pairing_server_static",
+		// TODO(b/299924782): Fix linking error
+		"libbinder_on_trusty_mock",
 
-		// java_import[_host] issues
-		// tradefed prebuilts depend on libprotobuf
-		"prebuilt_tradefed",
-		"prebuilt_tradefed-test-framework",
-		// handcrafted BUILD.bazel files in //prebuilts/...
-		"prebuilt_r8lib-prebuilt",
-		"prebuilt_sdk-core-lambda-stubs",
-		"prebuilt_android-support-collections-nodeps",
-		"prebuilt_android-arch-core-common-nodeps",
-		"prebuilt_android-arch-lifecycle-common-java8-nodeps",
-		"prebuilt_android-arch-lifecycle-common-nodeps",
-		"prebuilt_android-support-annotations-nodeps",
-		"prebuilt_android-arch-paging-common-nodeps",
-		"prebuilt_android-arch-room-common-nodeps",
-		// TODO(b/217750501) exclude_dirs property not supported
-		"prebuilt_kotlin-reflect",
-		"prebuilt_kotlin-stdlib",
-		"prebuilt_kotlin-stdlib-jdk7",
-		"prebuilt_kotlin-stdlib-jdk8",
-		"prebuilt_kotlin-test",
-		// TODO(b/217750501) exclude_files property not supported
-		"prebuilt_currysrc_org.eclipse",
+		// TODO(b/299943581): Depends on aidl filegroups with implicit headers
+		"libdataloader_aidl-cpp",
+		"libincremental_manager_aidl-cpp",
 
-		// TODO(b/266459895): re-enable libunwindstack
-		"libunwindstack",
-		"libunwindstack_stdout_log",
-		"libunwindstack_no_dex",
-		"libunwindstack_utils",
-		"unwind_reg_info",
-		"libunwindstack_local",
-		"unwind_for_offline",
-		"unwind",
-		"unwind_info",
-		"unwind_symbols",
-		"libEGL",
-		"libGLESv2",
-		"libc_malloc_debug",
-		"libcodec2_hidl@1.0",
-		"libcodec2_hidl@1.1",
-		"libcodec2_hidl@1.2",
-		"libfdtrack",
-		"libgui",
-		"libgui_bufferqueue_static",
-		"libmedia_codecserviceregistrant",
-		"libstagefright_bufferqueue_helper_novndk",
-		"libutils_test",
-		"libutilscallstack",
-		"mediaswcodec",
+		// TODO(b/299974637) Fix linking error
+		"libbinder_rpc_unstable",
 	}
 
 	// Bazel prod-mode allowlist. Modules in this list are built by Bazel
@@ -1602,14 +1663,6 @@
 		"test_com.android.neuralnetworks",
 		"libneuralnetworks",
 		"libneuralnetworks_static",
-	}
-
-	// Staging-mode allowlist. Modules in this list are only built
-	// by Bazel with --bazel-mode-staging. This list should contain modules
-	// which will soon be added to the prod allowlist.
-	// It is implicit that all modules in ProdMixedBuildsEnabledList will
-	// also be built - do not add them to this list.
-	StagingMixedBuildsEnabledList = []string{
 		// M13: media.swcodec launch
 		"com.android.media.swcodec",
 		"test_com.android.media.swcodec",
@@ -1617,20 +1670,26 @@
 		"libcodec2_hidl@1.0",
 	}
 
+	// Staging-mode allowlist. Modules in this list are only built
+	// by Bazel with --bazel-mode-staging. This list should contain modules
+	// which will soon be added to the prod allowlist.
+	// It is implicit that all modules in ProdMixedBuildsEnabledList will
+	// also be built - do not add them to this list.
+	StagingMixedBuildsEnabledList = []string{}
+
 	// These should be the libs that are included by the apexes in the ProdMixedBuildsEnabledList
 	ProdDclaMixedBuildsEnabledList = []string{
 		"libbase",
 		"libc++",
 		"libcrypto",
 		"libcutils",
-	}
-
-	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
-	StagingDclaMixedBuildsEnabledList = []string{
 		"libstagefright_flacdec",
 		"libutils",
 	}
 
+	// These should be the libs that are included by the apexes in the StagingMixedBuildsEnabledList
+	StagingDclaMixedBuildsEnabledList = []string{}
+
 	// TODO(b/269342245): Enable the rest of the DCLA libs
 	// "libssl",
 
@@ -1642,4 +1701,18 @@
 		"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 6119b08..d84499b 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -934,6 +934,19 @@
 	})
 }
 
+// Construct ApiLevel object from min_sdk_version string value
+func MinSdkVersionFromValue(ctx EarlyModuleContext, value string) ApiLevel {
+	if value == "" {
+		return NoneApiLevel
+	}
+	apiLevel, err := ApiLevelFromUser(ctx, value)
+	if err != nil {
+		ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
+		return NoneApiLevel
+	}
+	return apiLevel
+}
+
 // Implemented by apexBundle.
 type ApexTestInterface interface {
 	// Return true if the apex bundle is an apex_test
diff --git a/android/api_levels.go b/android/api_levels.go
index 44c8640..3f538c0 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -19,6 +19,7 @@
 	"encoding/json"
 	"fmt"
 	"strconv"
+	"strings"
 )
 
 func init() {
@@ -237,6 +238,14 @@
 	}
 }
 
+func uncheckedFinalIncrementalApiLevel(num int, increment int) ApiLevel {
+	return ApiLevel{
+		value:     strconv.Itoa(num) + "." + strconv.Itoa(increment),
+		number:    num,
+		isPreview: false,
+	}
+}
+
 var NoneApiLevel = ApiLevel{
 	value: "(no version)",
 	// Not 0 because we don't want this to compare equal with the first preview.
@@ -371,6 +380,22 @@
 		return FutureApiLevel
 	}
 
+	if strings.Contains(raw, ".") {
+		// Check prebuilt incremental API format MM.m for major (API level) and minor (incremental) revisions
+		parts := strings.Split(raw, ".")
+		if len(parts) != 2 {
+			panic(fmt.Errorf("Found unexpected version '%s' for incremental API - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", raw))
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			panic(fmt.Errorf("Unable to read version number for incremental api '%s'", raw))
+		}
+
+		apiLevel := uncheckedFinalIncrementalApiLevel(sdk, qpr)
+		return apiLevel
+	}
+
 	asInt, err := strconv.Atoi(raw)
 	if err != nil {
 		panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw))
diff --git a/android/bazel.go b/android/bazel.go
index 0d2c777..e764b18 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -21,7 +21,9 @@
 	"strings"
 
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android/allowlists"
@@ -152,8 +154,8 @@
 	HasHandcraftedLabel() bool
 	HandcraftedLabel() string
 	GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
-	ShouldConvertWithBp2build(ctx BazelConversionContext) bool
-	shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool
+	ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool
+	shouldConvertWithBp2build(shouldConvertModuleContext, shouldConvertParams) bool
 
 	// ConvertWithBp2build either converts the module to a Bazel build target or
 	// declares the module as unconvertible (for logging and metrics).
@@ -426,18 +428,53 @@
 	return ModuleIncompatibility
 }
 
+func isGoModule(module blueprint.Module) bool {
+	if _, ok := module.(*bootstrap.GoPackage); ok {
+		return true
+	}
+	if _, ok := module.(*bootstrap.GoBinary); ok {
+		return true
+	}
+	return false
+}
+
 // ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
 func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
+	// Special-case bootstrap_go_package and bootstrap_go_binary
+	// These do not implement Bazelable, but have been converted
+	if isGoModule(module) {
+		return true
+	}
 	b, ok := module.(Bazelable)
 	if !ok {
 		return false
 	}
-	return b.shouldConvertWithBp2build(ctx, module) || b.HasHandcraftedLabel()
+
+	return b.HasHandcraftedLabel() || b.shouldConvertWithBp2build(ctx, shouldConvertParams{
+		module:     module,
+		moduleDir:  ctx.OtherModuleDir(module),
+		moduleName: ctx.OtherModuleName(module),
+		moduleType: ctx.OtherModuleType(module),
+	})
+}
+
+type ShouldConvertWithBazelContext interface {
+	ModuleErrorf(format string, args ...interface{})
+	Module() Module
+	Config() Config
+	ModuleType() string
+	ModuleName() string
+	ModuleDir() string
 }
 
 // ShouldConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build
-func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx BazelConversionContext) bool {
-	return b.shouldConvertWithBp2build(ctx, ctx.Module())
+func (b *BazelModuleBase) ShouldConvertWithBp2build(ctx ShouldConvertWithBazelContext) bool {
+	return b.shouldConvertWithBp2build(ctx, shouldConvertParams{
+		module:     ctx.Module(),
+		moduleDir:  ctx.ModuleDir(),
+		moduleName: ctx.ModuleName(),
+		moduleType: ctx.ModuleType(),
+	})
 }
 
 type bazelOtherModuleContext interface {
@@ -455,20 +492,27 @@
 		arch == Riscv64 // TODO(b/262192655) Riscv64 toolchains are not currently supported.
 }
 
-func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext, module blueprint.Module) bool {
+type shouldConvertModuleContext interface {
+	ModuleErrorf(format string, args ...interface{})
+	Config() Config
+}
+
+type shouldConvertParams struct {
+	module     blueprint.Module
+	moduleType string
+	moduleDir  string
+	moduleName string
+}
+
+func (b *BazelModuleBase) shouldConvertWithBp2build(ctx shouldConvertModuleContext, p shouldConvertParams) bool {
 	if !b.bazelProps().Bazel_module.CanConvertToBazel {
 		return false
 	}
 
-	// In api_bp2build mode, all soong modules that can provide API contributions should be converted
-	// This is irrespective of its presence/absence in bp2build allowlists
-	if ctx.Config().BuildMode == ApiBp2build {
-		_, providesApis := module.(ApiProvider)
-		return providesApis
-	}
+	module := p.module
 
 	propValue := b.bazelProperties.Bazel_module.Bp2build_available
-	packagePath := moduleDirWithPossibleOverride(ctx, module)
+	packagePath := moduleDirWithPossibleOverride(ctx, module, p.moduleDir)
 
 	// Modules in unit tests which are enabled in the allowlist by type or name
 	// trigger this conditional because unit tests run under the "." package path
@@ -477,19 +521,19 @@
 		return true
 	}
 
-	moduleName := moduleNameWithPossibleOverride(ctx, module)
+	moduleName := moduleNameWithPossibleOverride(ctx, module, p.moduleName)
 	allowlist := ctx.Config().Bp2buildPackageConfig
 	moduleNameAllowed := allowlist.moduleAlwaysConvert[moduleName]
-	moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[ctx.OtherModuleType(module)]
+	moduleTypeAllowed := allowlist.moduleTypeAlwaysConvert[p.moduleType]
 	allowlistConvert := moduleNameAllowed || moduleTypeAllowed
 	if moduleNameAllowed && moduleTypeAllowed {
-		ctx.ModuleErrorf("A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert")
+		ctx.ModuleErrorf("A module %q of type %q cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert", moduleName, p.moduleType)
 		return false
 	}
 
 	if allowlist.moduleDoNotConvert[moduleName] {
 		if moduleNameAllowed {
-			ctx.ModuleErrorf("a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert")
+			ctx.ModuleErrorf("a module %q cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert", moduleName)
 		}
 		return false
 	}
@@ -572,8 +616,21 @@
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
 		return
 	}
+	// There may be cases where the target is created by a macro rather than in a BUILD file, those
+	// should be captured as well.
+	if bModule.HasHandcraftedLabel() {
+		// Defer to the BUILD target. Generating an additional target would
+		// cause a BUILD file conflict.
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "")
+		return
+	}
 	// TODO: b/285631638 - Differentiate between denylisted modules and missing bp2build capabilities.
-	if !bModule.shouldConvertWithBp2build(ctx, ctx.Module()) {
+	if !bModule.shouldConvertWithBp2build(ctx, shouldConvertParams{
+		module:     ctx.Module(),
+		moduleDir:  ctx.ModuleDir(),
+		moduleName: ctx.ModuleName(),
+		moduleType: ctx.ModuleType(),
+	}) {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
 		return
 	}
@@ -626,3 +683,21 @@
 	})
 	return validatedOutputFilePath
 }
+
+func RunsOn(hostSupported bool, deviceSupported bool, unitTest bool) []string {
+	var runsOn []string
+
+	if hostSupported && deviceSupported {
+		runsOn = []string{"host_without_device", "device"}
+	} else if hostSupported {
+		if unitTest {
+			runsOn = []string{"host_without_device"}
+		} else {
+			runsOn = []string{"host_with_device"}
+		}
+	} else if deviceSupported {
+		runsOn = []string{"device"}
+	}
+
+	return runsOn
+}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 94bc88b..4b98345 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -22,6 +22,7 @@
 	"os"
 	"path"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"sort"
 	"strings"
@@ -186,6 +187,8 @@
 
 	// Returns the depsets defined in Bazel's aquery response.
 	AqueryDepsets() []bazel.AqueryDepset
+
+	QueueBazelSandwichCqueryRequests(config Config) error
 }
 
 type bazelRunner interface {
@@ -264,6 +267,10 @@
 	m.BazelRequests[key] = true
 }
 
+func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+	panic("unimplemented")
+}
+
 func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
 	result, ok := m.LabelToOutputFiles[label]
 	if !ok {
@@ -424,6 +431,10 @@
 	panic("unimplemented")
 }
 
+func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+	panic("unimplemented")
+}
+
 func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
 	panic("unimplemented")
 }
@@ -1042,6 +1053,64 @@
 	allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
 )
 
+func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
+	result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+	labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$")
+	// Note that bazel "targets" are different from soong "targets", the bazel targets are
+	// synonymous with soong modules, and soong targets are a configuration a module is built in.
+	for _, target := range allowlists.BazelSandwichTargets {
+		match := labelRegex.FindStringSubmatch(target.Label)
+		if match == nil {
+			return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label)
+		}
+		if _, err := os.Stat(absolutePath(match[1])); err != nil {
+			if os.IsNotExist(err) {
+				// Ignore bazel sandwich targets that don't exist.
+				continue
+			} else {
+				return nil, err
+			}
+		}
+
+		var soongTarget Target
+		if target.Host {
+			soongTarget = config.BuildOSTarget
+		} else {
+			soongTarget = config.AndroidCommonTarget
+			if soongTarget.Os.Class != Device {
+				// kernel-build-tools seems to set the AndroidCommonTarget to a linux host
+				// target for some reason, disable device builds in that case.
+				continue
+			}
+		}
+
+		result = append(result, cqueryKey{
+			label:       target.Label,
+			requestType: cquery.GetOutputFiles,
+			configKey: configKey{
+				arch:   soongTarget.Arch.String(),
+				osType: soongTarget.Os,
+			},
+		})
+	}
+	return result, nil
+}
+
+// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in
+// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the
+// command line.
+func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+	requests, err := GetBazelSandwichCqueryRequests(config)
+	if err != nil {
+		return err
+	}
+	for _, request := range requests {
+		context.QueueBazelRequest(request.label, request.requestType, request.configKey)
+	}
+
+	return nil
+}
+
 // Issues commands to Bazel to receive results for all cquery requests
 // queued in the BazelContext.
 func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
@@ -1255,6 +1324,11 @@
 
 	executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
 	bazelOutDir := path.Join(executionRoot, "bazel-out")
+	rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot)
+	if err != nil {
+		ctx.Errorf("%s", err.Error())
+	}
+	dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1)
 	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
 		// nil build statements are a valid case where we do not create an action because it is
 		// unnecessary or handled by other processing
@@ -1286,7 +1360,8 @@
 					})
 				}
 			}
-			createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset)
+			createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset, dotdotsToOutRoot)
+
 			desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
 			rule.Build(fmt.Sprintf("bazel %d", index), desc)
 			continue
@@ -1307,7 +1382,11 @@
 			WriteFileRuleVerbatim(ctx, out, "")
 		case "FileWrite", "SourceSymlinkManifest":
 			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
-			WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
+			if buildStatement.IsExecutable {
+				WriteExecutableFileRuleVerbatim(ctx, out, buildStatement.FileContents)
+			} else {
+				WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
+			}
 		case "SymlinkTree":
 			// build-runfiles arguments are the manifest file and the target directory
 			// where it creates the symlink tree according to this manifest (and then
@@ -1331,6 +1410,24 @@
 			panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
 		}
 	}
+
+	// Create phony targets for all the bazel sandwich output files
+	requests, err := GetBazelSandwichCqueryRequests(ctx.Config())
+	if err != nil {
+		ctx.Errorf(err.Error())
+	}
+	for _, request := range requests {
+		files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey)
+		if err != nil {
+			ctx.Errorf(err.Error())
+		}
+		filesAsPaths := make([]Path, 0, len(files))
+		for _, file := range files {
+			filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file))
+		}
+		ctx.Phony("bazel_sandwich", filesAsPaths...)
+	}
+	ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich"))
 }
 
 // Returns a out dir path for a sandboxed mixed build action
@@ -1344,7 +1441,7 @@
 }
 
 // Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset) {
+func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) {
 	// executionRoot is the action cwd.
 	if buildStatement.ShouldRunInSbox {
 		// mkdir -p ensures that the directory exists when run via sbox
@@ -1367,14 +1464,17 @@
 		cmd.Flag(pair.Key + "=" + pair.Value)
 	}
 
+	command := buildStatement.Command
+	command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot)
+
 	// The actual Bazel action.
-	if len(buildStatement.Command) > 16*1024 {
+	if len(command) > 16*1024 {
 		commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
-		WriteFileRule(ctx, commandFile, buildStatement.Command)
+		WriteFileRule(ctx, commandFile, command)
 
 		cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
 	} else {
-		cmd.Text(buildStatement.Command)
+		cmd.Text(command)
 	}
 
 	for _, outputPath := range buildStatement.OutputPaths {
@@ -1403,6 +1503,9 @@
 			cmd.Implicit(PathForPhony(ctx, otherDepsetName))
 		}
 	}
+	for _, implicitPath := range buildStatement.ImplicitDeps {
+		cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath))
+	}
 
 	if depfile := buildStatement.Depfile; depfile != nil {
 		// The paths in depfile are relative to `executionRoot`.
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index e08a471..9a3c8fc 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -181,7 +181,7 @@
 
 		cmd := RuleBuilderCommand{}
 		ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
-		createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+		createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
 		if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
 			t.Errorf("expected: [%s], actual: [%s]", expected, actual)
 		}
@@ -224,7 +224,7 @@
 
 	cmd := RuleBuilderCommand{}
 	ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
-	createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+	createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
 	// Assert that the output is generated in an intermediate directory
 	// fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one"
 	if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual {
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 8956a18..86829ce 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -88,6 +88,8 @@
 	EarlyModulePathContext
 	BazelConversionContext
 
+	ModuleName() string
+	ModuleType() string
 	ModuleErrorf(fmt string, args ...interface{})
 	PropertyErrorf(property, fmt string, args ...interface{})
 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
@@ -124,6 +126,7 @@
 		labels.Includes = []bazel.Label{}
 		return labels
 	}
+	modules = FirstUniqueStrings(modules)
 	for _, module := range modules {
 		bpText := module
 		if m := SrcIsModule(module); m == "" {
@@ -202,6 +205,21 @@
 	return labels
 }
 
+func BazelLabelForSrcPatternExcludes(ctx BazelConversionPathContext, dir, pattern string, excludes []string) bazel.LabelList {
+	topRelPaths, err := ctx.GlobWithDeps(filepath.Join(dir, pattern), excludes)
+	if err != nil {
+		ctx.ModuleErrorf("Could not search dir: %s for pattern %s due to %v\n", dir, pattern, err)
+	}
+	// An intermediate list of labels relative to `dir` that assumes that there no subpacakges beneath `dir`
+	dirRelLabels := []bazel.Label{}
+	for _, topRelPath := range topRelPaths {
+		dirRelPath := Rel(ctx, dir, topRelPath)
+		dirRelLabels = append(dirRelLabels, bazel.Label{Label: "./" + dirRelPath})
+	}
+	// Return the package boudary resolved labels
+	return TransformSubpackagePaths(ctx.Config(), dir, bazel.MakeLabelList(dirRelLabels))
+}
+
 // Returns true if a prefix + components[:i] is a package boundary.
 //
 // A package boundary is determined by a BUILD file in the directory. This can happen in 2 cases:
@@ -375,7 +393,13 @@
 		if m, tag := SrcIsModuleWithTag(p); m != "" {
 			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
 			if l != nil && !InList(l.Label, expandedExcludes) {
-				l.OriginalModuleName = fmt.Sprintf(":%s", m)
+				if strings.HasPrefix(m, "//") {
+					// this is a module in a soong namespace
+					// It appears as //<namespace>:<module_name> in srcs, and not ://<namespace>:<module_name>
+					l.OriginalModuleName = m
+				} else {
+					l.OriginalModuleName = fmt.Sprintf(":%s", m)
+				}
 				labels.Includes = append(labels.Includes, *l)
 			}
 		} else {
@@ -430,7 +454,7 @@
 
 func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
 	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
-	if !convertedToBazel(ctx, module) {
+	if !convertedToBazel(ctx, module) || isGoModule(module) {
 		return bp2buildModuleLabel(ctx, module)
 	}
 	b, _ := module.(Bazelable)
@@ -458,8 +482,8 @@
 }
 
 func bp2buildModuleLabel(ctx BazelConversionContext, module blueprint.Module) string {
-	moduleName := moduleNameWithPossibleOverride(ctx, module)
-	moduleDir := moduleDirWithPossibleOverride(ctx, module)
+	moduleName := moduleNameWithPossibleOverride(ctx, module, ctx.OtherModuleName(module))
+	moduleDir := moduleDirWithPossibleOverride(ctx, module, ctx.OtherModuleDir(module))
 	if moduleDir == Bp2BuildTopLevel {
 		moduleDir = ""
 	}
diff --git a/android/bazel_paths_test.go b/android/bazel_paths_test.go
index 60c0a14..bed719c 100644
--- a/android/bazel_paths_test.go
+++ b/android/bazel_paths_test.go
@@ -15,10 +15,12 @@
 package android
 
 import (
+	"fmt"
 	"path/filepath"
 	"testing"
 
 	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 )
@@ -113,8 +115,9 @@
 
 type TestBazelConversionPathContext struct {
 	TestBazelConversionContext
-	moduleDir string
-	cfg       Config
+	moduleDir       string
+	cfg             Config
+	mockGlobResults *[]string
 }
 
 func (ctx *TestBazelConversionPathContext) AddNinjaFileDeps(...string) {
@@ -122,7 +125,10 @@
 }
 
 func (ctx *TestBazelConversionPathContext) GlobWithDeps(string, []string) ([]string, error) {
-	panic("Unimplemented")
+	if ctx.mockGlobResults == nil {
+		return []string{}, fmt.Errorf("Set mock glob results first")
+	}
+	return *ctx.mockGlobResults, nil
 }
 
 func (ctx *TestBazelConversionPathContext) PropertyErrorf(string, string, ...interface{}) {
@@ -157,6 +163,14 @@
 	return ctx.moduleDir
 }
 
+func (ctx *TestBazelConversionPathContext) ModuleName() string {
+	panic("Unimplemented")
+}
+
+func (ctx *TestBazelConversionPathContext) ModuleType() string {
+	panic("Unimplemented")
+}
+
 func TestTransformSubpackagePath(t *testing.T) {
 	cfg := NullConfig("out", "out/soong")
 	cfg.fs = pathtools.MockFs(map[string][]byte{
@@ -181,3 +195,46 @@
 		}
 	}
 }
+
+// Check that the files in a specific directory are returned with labels that respect package boundaries
+// Since the test uses a mock for GlobWithDeps, the params passed to BazelLabelForSrcPatternExcludes are no-ops
+func TestBazelLabelForSrcPatternExcludes(t *testing.T) {
+	cfg := NullConfig("out", "out/soong")
+	cfg.fs = pathtools.MockFs(map[string][]byte{
+		"x/Android.bp":   nil,
+		"x/y/Android.bp": nil,
+		// .proto files
+		"foo.proto":     nil,
+		"x/bar.proto":   nil,
+		"x/baz.proto":   nil,
+		"x/y/qux.proto": nil,
+	})
+
+	var ctx BazelConversionPathContext = &TestBazelConversionPathContext{
+		cfg: cfg,
+	}
+
+	// Root dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"foo.proto", "x/bar.proto", "x/baz.proto", "x/y/qux.proto"}
+	actualLabelsFromRoot := BazelLabelForSrcPatternExcludes(ctx, ".", "**/*.proto", []string{})
+	expectedLabelsAsString := []string{"foo.proto", "//x:bar.proto", "//x:baz.proto", "//x/y:qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to root directory", expectedLabelsAsString[i], actual.Label)
+	}
+
+	// x dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"x/bar.proto", "x/baz.proto", "x/y/qux.proto"}
+	actualLabelsFromRoot = BazelLabelForSrcPatternExcludes(ctx, "x", "**/*.proto", []string{})
+	expectedLabelsAsString = []string{"bar.proto", "baz.proto", "//x/y:qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to x directory", expectedLabelsAsString[i], actual.Label)
+	}
+
+	// y dir
+	ctx.(*TestBazelConversionPathContext).mockGlobResults = &[]string{"x/y/qux.proto"}
+	actualLabelsFromRoot = BazelLabelForSrcPatternExcludes(ctx, "x/y", "**/*.proto", []string{})
+	expectedLabelsAsString = []string{"qux.proto"}
+	for i, actual := range actualLabelsFromRoot.Includes {
+		AssertStringEquals(t, "Error in finding src labels relative to x/y directory", expectedLabelsAsString[i], actual.Label)
+	}
+}
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 13fd408..15d3a6b 100644
--- a/android/bazel_test.go
+++ b/android/bazel_test.go
@@ -252,7 +252,7 @@
 		{
 			description:    "module in name allowlist and type allowlist fails",
 			shouldConvert:  false,
-			expectedErrors: []string{"A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"},
+			expectedErrors: []string{"A module \"foo\" of type \"rule1\" cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"},
 			module: TestBazelModule{
 				TestModuleInfo: bazel.TestModuleInfo{
 					ModuleName: "foo",
@@ -273,7 +273,7 @@
 		{
 			description:    "module in allowlist and denylist fails",
 			shouldConvert:  false,
-			expectedErrors: []string{"a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"},
+			expectedErrors: []string{"a module \"foo\" cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"},
 			module: TestBazelModule{
 				TestModuleInfo: bazel.TestModuleInfo{
 					ModuleName: "foo",
@@ -373,7 +373,14 @@
 				allowlist: test.allowlist,
 			}
 
-			shouldConvert := test.module.shouldConvertWithBp2build(bcc, test.module.TestModuleInfo)
+			shouldConvert := test.module.shouldConvertWithBp2build(bcc,
+				shouldConvertParams{
+					module:     test.module.TestModuleInfo,
+					moduleDir:  test.module.TestModuleInfo.Dir,
+					moduleType: test.module.TestModuleInfo.Typ,
+					moduleName: test.module.TestModuleInfo.ModuleName,
+				},
+			)
 			if test.shouldConvert != shouldConvert {
 				t.Errorf("Module shouldConvert expected to be: %v, but was: %v", test.shouldConvert, shouldConvert)
 			}
diff --git a/android/config.go b/android/config.go
index 2a243ee..645a263 100644
--- a/android/config.go
+++ b/android/config.go
@@ -87,7 +87,6 @@
 	SymlinkForestMarker string
 	Bp2buildMarker      string
 	BazelQueryViewDir   string
-	BazelApiBp2buildDir string
 	ModuleGraphFile     string
 	ModuleActionsFile   string
 	DocFile             string
@@ -121,9 +120,6 @@
 	// express build semantics.
 	GenerateQueryView
 
-	// Generate BUILD files for API contributions to API surfaces
-	ApiBp2build
-
 	// Create a JSON representation of the module graph and exit.
 	GenerateModuleGraph
 
@@ -170,6 +166,19 @@
 	return c.config.TestProductVariables != nil
 }
 
+// DisableHiddenApiChecks returns true if hiddenapi checks have been disabled.
+// For 'eng' target variant hiddenapi checks are disabled by default for performance optimisation,
+// but can be enabled by setting environment variable ENABLE_HIDDENAPI_FLAGS=true.
+// For other target variants hiddenapi check are enabled by default but can be disabled by
+// setting environment variable UNSAFE_DISABLE_HIDDENAPI_FLAGS=true.
+// If both ENABLE_HIDDENAPI_FLAGS=true and UNSAFE_DISABLE_HIDDENAPI_FLAGS=true, then
+// ENABLE_HIDDENAPI_FLAGS=true will be triggered and hiddenapi checks will be considered enabled.
+func (c Config) DisableHiddenApiChecks() bool {
+	return !c.IsEnvTrue("ENABLE_HIDDENAPI_FLAGS") &&
+		(c.IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") ||
+			Bool(c.productVariables.Eng))
+}
+
 // MaxPageSizeSupported returns the max page size supported by the device. This
 // value will define the ELF segment alignment for binaries (executables and
 // shared libraries).
@@ -177,6 +186,12 @@
 	return String(c.config.productVariables.DeviceMaxPageSizeSupported)
 }
 
+// PageSizeAgnostic returns true when AOSP is page size agnostic,
+// othersise it returns false.
+func (c Config) PageSizeAgnostic() bool {
+	return Bool(c.config.productVariables.DevicePageSizeAgnostic)
+}
+
 // The release version passed to aconfig, derived from RELEASE_VERSION
 func (c Config) ReleaseVersion() string {
 	return c.config.productVariables.ReleaseVersion
@@ -187,6 +202,12 @@
 	return c.config.productVariables.ReleaseAconfigValueSets
 }
 
+// The flag default permission value passed to aconfig
+// derived from RELEASE_ACONFIG_FLAG_DEFAULT_PERMISSION
+func (c Config) ReleaseAconfigFlagDefaultPermission() string {
+	return c.config.productVariables.ReleaseAconfigFlagDefaultPermission
+}
+
 // 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.
@@ -401,6 +422,12 @@
 	return nil
 }
 
+type productVariableStarlarkRepresentation struct {
+	soongType   string
+	selectable  bool
+	archVariant bool
+}
+
 func saveToBazelConfigFile(config *ProductVariables, outDir string) error {
 	dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
 	err := createDirIfNonexistent(dir, os.ModePerm)
@@ -408,32 +435,39 @@
 		return fmt.Errorf("Could not create dir %s: %s", dir, err)
 	}
 
-	nonArchVariantProductVariables := []string{}
-	archVariantProductVariables := []string{}
+	allProductVariablesType := reflect.TypeOf((*ProductVariables)(nil)).Elem()
+	productVariablesInfo := make(map[string]productVariableStarlarkRepresentation)
 	p := variableProperties{}
 	t := reflect.TypeOf(p.Product_variables)
 	for i := 0; i < t.NumField(); i++ {
 		f := t.Field(i)
-		nonArchVariantProductVariables = append(nonArchVariantProductVariables, strings.ToLower(f.Name))
-		if proptools.HasTag(f, "android", "arch_variant") {
-			archVariantProductVariables = append(archVariantProductVariables, strings.ToLower(f.Name))
+		archVariant := proptools.HasTag(f, "android", "arch_variant")
+		if mainProductVariablesStructField, ok := allProductVariablesType.FieldByName(f.Name); ok {
+			productVariablesInfo[f.Name] = productVariableStarlarkRepresentation{
+				soongType:   stringRepresentationOfSimpleType(mainProductVariablesStructField.Type),
+				selectable:  true,
+				archVariant: archVariant,
+			}
+		} else {
+			panic("Unknown variable " + f.Name)
 		}
 	}
 
-	nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0)
-	if err != nil {
-		return fmt.Errorf("cannot marshal product variable data: %s", err.Error())
-	}
-
-	archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0)
-	if err != nil {
-		return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
-	}
-
 	err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(`
-product_var_constraints = %s
-arch_variant_product_var_constraints = %s
-`, nonArchVariantProductVariablesJson, archVariantProductVariablesJson)), 0644)
+# product_var_constant_info is a map of product variables to information about them. The fields are:
+# - soongType: The type of the product variable as it appears in soong's ProductVariables struct.
+#              examples are string, bool, int, *bool, *string, []string, etc. This may be an overly
+#              conservative estimation of the type, for example a *bool could oftentimes just be a
+#              bool that defaults to false.
+# - selectable: if this product variable can be selected on in Android.bp/build files. This means
+#               it's listed in the "variableProperties" soong struct. Currently all variables in
+#               this list are selectable because we only need the selectable ones at the moment,
+#               but the list may be expanded later.
+# - archVariant: If the variable is tagged as arch variant in the "variableProperties" struct.
+product_var_constant_info = %s
+product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable]
+arch_variant_product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable and v.archVariant]
+`, starlark_fmt.PrintAny(productVariablesInfo, 0))), 0644)
 	if err != nil {
 		return fmt.Errorf("Could not write .bzl config file %s", err)
 	}
@@ -446,6 +480,23 @@
 	return nil
 }
 
+func stringRepresentationOfSimpleType(ty reflect.Type) string {
+	switch ty.Kind() {
+	case reflect.String:
+		return "string"
+	case reflect.Bool:
+		return "bool"
+	case reflect.Int:
+		return "int"
+	case reflect.Slice:
+		return "[]" + stringRepresentationOfSimpleType(ty.Elem())
+	case reflect.Pointer:
+		return "*" + stringRepresentationOfSimpleType(ty.Elem())
+	default:
+		panic("unimplemented type: " + ty.Kind().String())
+	}
+}
+
 // NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
 // use the android package.
 func NullConfig(outDir, soongOutDir string) Config {
@@ -586,7 +637,6 @@
 	setBuildMode(cmdArgs.SymlinkForestMarker, SymlinkForest)
 	setBuildMode(cmdArgs.Bp2buildMarker, Bp2build)
 	setBuildMode(cmdArgs.BazelQueryViewDir, GenerateQueryView)
-	setBuildMode(cmdArgs.BazelApiBp2buildDir, ApiBp2build)
 	setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph)
 	setBuildMode(cmdArgs.DocFile, GenerateDocFile)
 	setBazelMode(cmdArgs.BazelMode, "--bazel-mode", BazelProdMode)
@@ -1607,11 +1657,18 @@
 	return HasAnyPrefix(path, c.productVariables.MemtagHeapSyncIncludePaths) && !c.MemtagHeapDisabledForPath(path)
 }
 
+func (c *config) HWASanDisabledForPath(path string) bool {
+	if len(c.productVariables.HWASanExcludePaths) == 0 {
+		return false
+	}
+	return HasAnyPrefix(path, c.productVariables.HWASanExcludePaths)
+}
+
 func (c *config) HWASanEnabledForPath(path string) bool {
 	if len(c.productVariables.HWASanIncludePaths) == 0 {
 		return false
 	}
-	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths)
+	return HasAnyPrefix(path, c.productVariables.HWASanIncludePaths) && !c.HWASanDisabledForPath(path)
 }
 
 func (c *config) VendorConfig(name string) VendorConfig {
@@ -1737,30 +1794,6 @@
 	return c.PlatformSepolicyVersion()
 }
 
-func (c *deviceConfig) BoardPlatVendorPolicy() []string {
-	return c.config.productVariables.BoardPlatVendorPolicy
-}
-
-func (c *deviceConfig) BoardReqdMaskPolicy() []string {
-	return c.config.productVariables.BoardReqdMaskPolicy
-}
-
-func (c *deviceConfig) BoardSystemExtPublicPrebuiltDirs() []string {
-	return c.config.productVariables.BoardSystemExtPublicPrebuiltDirs
-}
-
-func (c *deviceConfig) BoardSystemExtPrivatePrebuiltDirs() []string {
-	return c.config.productVariables.BoardSystemExtPrivatePrebuiltDirs
-}
-
-func (c *deviceConfig) BoardProductPublicPrebuiltDirs() []string {
-	return c.config.productVariables.BoardProductPublicPrebuiltDirs
-}
-
-func (c *deviceConfig) BoardProductPrivatePrebuiltDirs() []string {
-	return c.config.productVariables.BoardProductPrivatePrebuiltDirs
-}
-
 func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDir() string {
 	return String(c.config.productVariables.SystemExtSepolicyPrebuiltApiDir)
 }
@@ -1909,6 +1942,10 @@
 	return c.config.productVariables.RequiresInsecureExecmemForSwiftshader
 }
 
+func (c *deviceConfig) Release_aidl_use_unfrozen() bool {
+	return Bool(c.config.productVariables.Release_aidl_use_unfrozen)
+}
+
 func (c *config) SelinuxIgnoreNeverallows() bool {
 	return c.productVariables.SelinuxIgnoreNeverallows
 }
@@ -2022,3 +2059,7 @@
 func (c *config) GetApiLibraries() map[string]struct{} {
 	return c.apiLibraries
 }
+
+func (c *deviceConfig) CheckVendorSeappViolations() bool {
+	return Bool(c.config.productVariables.CheckVendorSeappViolations)
+}
diff --git a/android/defs.go b/android/defs.go
index 18eed2d..b28d2fa 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -107,8 +107,8 @@
 
 	Cat = pctx.AndroidStaticRule("Cat",
 		blueprint.RuleParams{
-			Command:     "cat $in > $out",
-			Description: "concatenate licenses $out",
+			Command:     "rm -f $out && cat $in > $out",
+			Description: "concatenate files to $out",
 		})
 
 	// ubuntu 14.04 offcially use dash for /bin/sh, and its builtin echo command
@@ -116,7 +116,7 @@
 	// content to file.
 	writeFile = pctx.AndroidStaticRule("writeFile",
 		blueprint.RuleParams{
-			Command:     `/bin/bash -c 'echo -e -n "$$0" > $out' $content`,
+			Command:     `rm -f $out && /bin/bash -c 'echo -e -n "$$0" > $out' $content`,
 			Description: "writing file $out",
 		},
 		"content")
@@ -209,12 +209,14 @@
 	buildWriteFileRule(ctx, outputFile, content)
 }
 
-func CatFileRule(ctx BuilderContext, paths Paths, outputFile WritablePath) {
+// WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result
+func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
+	intermediate := PathForIntermediates(ctx, "write_executable_file_intermediates").Join(ctx, outputFile.String())
+	WriteFileRuleVerbatim(ctx, intermediate, content)
 	ctx.Build(pctx, BuildParams{
-		Rule:        Cat,
-		Inputs:      paths,
-		Output:      outputFile,
-		Description: "combine files to " + outputFile.Base(),
+		Rule:   CpExecutable,
+		Output: outputFile,
+		Input:  intermediate,
 	})
 }
 
diff --git a/android/filegroup.go b/android/filegroup.go
index 3b86655..6cc9232 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -24,6 +24,7 @@
 	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -141,8 +142,14 @@
 			attrs)
 	} else {
 		if fg.ShouldConvertToProtoLibrary(ctx) {
+			pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), bazel.MakeLabelList(srcs.Value.Includes))
+			if len(pkgToSrcs) > 1 {
+				ctx.ModuleErrorf("TODO: Add bp2build support for multiple package .protosrcs in filegroup")
+				return
+			}
+			pkg := SortedKeys(pkgToSrcs)[0]
 			attrs := &ProtoAttrs{
-				Srcs:                srcs,
+				Srcs:                bazel.MakeLabelListAttribute(pkgToSrcs[pkg]),
 				Strip_import_prefix: fg.properties.Path,
 			}
 
@@ -151,13 +158,39 @@
 				// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
 				"manual",
 			}
+			if pkg != ctx.ModuleDir() {
+				// Since we are creating the proto_library in a subpackage, create an import_prefix relative to the current package
+				if rel, err := filepath.Rel(ctx.ModuleDir(), pkg); err != nil {
+					ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
+				} else if rel != "." {
+					attrs.Import_prefix = &rel
+					// Strip the package prefix
+					attrs.Strip_import_prefix = proptools.StringPtr("")
+				}
+			}
+
 			ctx.CreateBazelTargetModule(
 				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
 				CommonAttributes{
-					Name: fg.Name() + convertedProtoLibrarySuffix,
+					Name: fg.Name() + "_proto",
+					Dir:  proptools.StringPtr(pkg),
 					Tags: bazel.MakeStringListAttribute(tags),
 				},
 				attrs)
+
+			// Create an alias in the current dir. The actual target might exist in a different package, but rdeps
+			// can reliabily use this alias
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{Rule_class: "alias"},
+				CommonAttributes{
+					Name: fg.Name() + convertedProtoLibrarySuffix,
+					// TODO(b/246997908): we can remove this tag if we could figure out a solution for this bug.
+					Tags: bazel.MakeStringListAttribute(tags),
+				},
+				&bazelAliasAttributes{
+					Actual: bazel.MakeLabelAttribute("//" + pkg + ":" + fg.Name() + "_proto"),
+				},
+			)
 		}
 
 		// TODO(b/242847534): Still convert to a filegroup because other unconverted
diff --git a/android/module.go b/android/module.go
index 384776a..516810f 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1021,6 +1021,11 @@
 	Applicable_licenses bazel.LabelListAttribute
 
 	Testonly *bool
+
+	// Dir is neither a Soong nor Bazel target attribute
+	// If set, the bazel target will be created in this directory
+	// If unset, the bazel target will default to be created in the directory of the visited soong module
+	Dir *string
 }
 
 // constraintAttributes represents Bazel attributes pertaining to build constraints,
@@ -1366,22 +1371,22 @@
 		for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() {
 			configToBools := enabledPropertyOverrides.ConfigurableValues[axis]
 			for cfg, val := range configToBools {
-				if axis != bazel.OsConfigurationAxis || osSupport[cfg] {
+				if axis != bazel.OsConfigurationAxis || osSupport[cfg] || val /*If enabled is explicitly requested via overrides */ {
 					enabledProperty.SetSelectValue(axis, cfg, &val)
 				}
 			}
 		}
 	}
 
-	productConfigEnabledLabels := []bazel.Label{}
+	productConfigEnabledAttribute := bazel.LabelListAttribute{}
 	// TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we
 	// should handle it correctly
 	if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice {
 		// If the module is not enabled by default, then we can check if a
 		// product variable enables it
-		productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
+		productConfigEnabledAttribute = productVariableConfigEnableAttribute(ctx)
 
-		if len(productConfigEnabledLabels) > 0 {
+		if len(productConfigEnabledAttribute.ConfigurableValues) > 0 {
 			// In this case, an existing product variable configuration overrides any
 			// module-level `enable: false` definition
 			newValue := true
@@ -1389,10 +1394,6 @@
 		}
 	}
 
-	productConfigEnabledAttribute := bazel.MakeLabelListAttribute(bazel.LabelList{
-		productConfigEnabledLabels, nil,
-	})
-
 	platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
 		bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil},
 		bazel.LabelList{[]bazel.Label{}, nil})
@@ -1417,37 +1418,73 @@
 	moduleEnableConstraints := bazel.LabelListAttribute{}
 	moduleEnableConstraints.Append(platformEnabledAttribute)
 	moduleEnableConstraints.Append(productConfigEnabledAttribute)
+	addCompatibilityConstraintForCompileMultilib(ctx, &moduleEnableConstraints)
 
 	return constraintAttributes{Target_compatible_with: moduleEnableConstraints}
 }
 
+var (
+	incompatible = bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil}
+)
+
+// 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) {
+	mod := ctx.Module().base()
+	multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice())
+
+	switch multilib {
+	case "32":
+		// Add an incompatibility constraint for all known 64-bit arches
+		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm64", incompatible)
+		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86_64", incompatible)
+		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "riscv64", incompatible)
+	case "64":
+		// Add an incompatibility constraint for all known 32-bit arches
+		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm", incompatible)
+		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86", incompatible)
+	case "both":
+		// Do nothing: "both" is trivially compatible with 32-bit and 64-bit
+		// The top level rule (e.g. apex/partition) will be responsible for building this module in both variants via an
+		// outgoing_transition.
+	default: // e.g. first, common
+		// TODO - b/299135307: Add bp2build support for these properties.
+	}
+
+}
+
 // Check product variables for `enabled: true` flag override.
 // Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
+func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
+	result := bazel.LabelListAttribute{}
 	productVariableProps := ProductVariableProperties(ctx, ctx.Module())
-	productConfigEnablingTargets := []bazel.Label{}
-	const propName = "Enabled"
-	if productConfigProps, exists := productVariableProps[propName]; exists {
+	if productConfigProps, exists := productVariableProps["Enabled"]; exists {
 		for productConfigProp, prop := range productConfigProps {
 			flag, ok := prop.(*bool)
 			if !ok {
-				ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
+				ctx.ModuleErrorf("Could not convert product variable enabled property")
 			}
 
-			if *flag {
+			if flag == nil {
+				// soong config var is not used to set `enabled`. nothing to do.
+				continue
+			} else if *flag {
 				axis := productConfigProp.ConfigurationAxis()
-				targetLabel := axis.SelectKey(productConfigProp.SelectKey())
-				productConfigEnablingTargets = append(productConfigEnablingTargets, bazel.Label{
-					Label: targetLabel,
-				})
+				result.SetSelectValue(axis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{{Label: "@platforms//:incompatible"}}))
+				result.SetSelectValue(axis, productConfigProp.SelectKey(), bazel.LabelList{Includes: []bazel.Label{}})
+			} else if scp, isSoongConfigProperty := productConfigProp.(SoongConfigProperty); isSoongConfigProperty && scp.value == bazel.ConditionsDefaultConfigKey {
+				// productVariableConfigEnableAttribute runs only if `enabled: false` is set at the top-level outside soong_config_variables
+				// conditions_default { enabled: false} is a no-op in this case
+				continue
 			} else {
 				// TODO(b/210546943): handle negative case where `enabled: false`
-				ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943", proptools.PropertyNameForField(propName))
+				ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943")
 			}
 		}
 	}
 
-	return productConfigEnablingTargets
+	return result
 }
 
 // A ModuleBase object contains the properties that are common to all Android
@@ -4029,43 +4066,26 @@
 	JavaBp2buildTargetName() string
 }
 
-// PartitionXsdSrcs partitions srcs into xsd_config modules and others
-// Since xsd_config are soong modules, we cannot use file extension for partitioning
-func PartitionXsdSrcs(ctx BazelConversionPathContext, srcs []string) ([]string, []string) {
-	//isXsd returns true if src is a soong module of type xsd_config
-	isXsd := func(src string) bool {
-		mod, exists := ctx.ModuleFromName(src)
+// XsdModuleToTargetName is a function that takes an XsdConfigBp2buildTarget
+type XsdModuleToTargetName func(xsd XsdConfigBp2buildTargets) string
+
+// XsdLabelMapper returns a bazel.LabelMapper for partitioning XSD sources/headers given an
+// XsdModuleToTargetName function.
+func XsdLabelMapper(targetName XsdModuleToTargetName) bazel.LabelMapper {
+	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+		mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
 		if !exists {
-			return false
+			return label.Label, false
 		}
-		_, _isXsd := mod.(XsdConfigBp2buildTargets)
-		return _isXsd
-	}
-	nonXsd := []string{}
-	xsd := []string{}
-
-	for _, src := range srcs {
-		if isXsd(src) {
-			xsd = append(xsd, src)
-		} else {
-			nonXsd = append(nonXsd, src)
+		xsdMod, isXsd := mod.(XsdConfigBp2buildTargets)
+		if !isXsd {
+			return label.Label, false
 		}
-	}
 
-	return nonXsd, xsd
-}
-
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-{cpp|java}
-// The new target name is provided by the `targetName` callback function
-func XsdConfigBp2buildTarget(ctx BazelConversionPathContext, mod blueprint.Module, targetName func(xsd XsdConfigBp2buildTargets) string) string {
-	xsd, isXsd := mod.(XsdConfigBp2buildTargets)
-	if !isXsd {
-		ctx.ModuleErrorf("xsdConfigJavaTarget called on %v, which is not an xsd_config", mod)
+		// Remove the base module name
+		ret := strings.TrimSuffix(label.Label, mod.Name())
+		// Append the language specific target name
+		ret += targetName(xsdMod)
+		return ret, true
 	}
-	ret := BazelModuleLabel(ctx, mod)
-	// Remove the base module name
-	ret = strings.TrimSuffix(ret, mod.Name())
-	// Append the language specific target name
-	ret += targetName(xsd)
-	return ret
 }
diff --git a/android/mutator.go b/android/mutator.go
index 2ec051e..41477b8 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/bazel"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+	"path/filepath"
 
 	"github.com/google/blueprint"
 )
@@ -230,6 +231,7 @@
 	BazelConversionPathContext
 
 	CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
+	CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
 }
 
 // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
@@ -757,6 +759,27 @@
 	mod.base().addBp2buildInfo(info)
 }
 
+// Returns the directory in which the bazel target will be generated
+// If ca.Dir is not nil, use that
+// Otherwise default to the directory of the soong module
+func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
+	dir := t.OtherModuleDir(t.Module())
+	if ca.Dir != nil {
+		dir = *ca.Dir
+		// Restrict its use to dirs that contain an Android.bp file.
+		// There are several places in bp2build where we use the existence of Android.bp/BUILD on the filesystem
+		// to curate a compatible label for src files (e.g. headers for cc).
+		// If we arbritrarily create BUILD files, then it might render those curated labels incompatible.
+		if exists, _, _ := t.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists {
+			t.ModuleErrorf("Cannot use ca.Dir to create a BazelTarget in dir: %v since it does not contain an Android.bp file", dir)
+		}
+
+		// Set ca.Dir to nil so that it does not get emitted to the BUILD files
+		ca.Dir = nil
+	}
+	return dir
+}
+
 func (t *topDownMutatorContext) CreateBazelConfigSetting(
 	csa bazel.ConfigSettingAttributes,
 	ca CommonAttributes,
@@ -851,7 +874,7 @@
 	constraintAttributes := commonAttrs.fillCommonBp2BuildModuleAttrs(t, enabledProperty)
 	mod := t.Module()
 	info := bp2buildInfo{
-		Dir:             t.OtherModuleDir(mod),
+		Dir:             dirForBazelTargetGeneration(t, &commonAttrs),
 		BazelProps:      bazelProps,
 		CommonAttrs:     commonAttrs,
 		ConstraintAttrs: constraintAttributes,
diff --git a/android/neverallow.go b/android/neverallow.go
index 24031ba..2be6a74 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -60,6 +60,7 @@
 	AddNeverAllowRules(createBp2BuildRule())
 	AddNeverAllowRules(createCcStubsRule())
 	AddNeverAllowRules(createJavaExcludeStaticLibsRule())
+	AddNeverAllowRules(createProhibitHeaderOnlyRule())
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -264,6 +265,13 @@
 		Because("exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api")
 }
 
+func createProhibitHeaderOnlyRule() Rule {
+	return NeverAllow().
+		Without("name", "framework-minus-apex-headers").
+		With("headers_only", "true").
+		Because("headers_only can only be used for generating framework-minus-apex headers for non-updatable modules")
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 2a938b8..b2620ef 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -361,6 +361,21 @@
 			`exclude_static_libs property is only allowed for java modules defined in build/soong, libcore, and frameworks/base/api`,
 		},
 	},
+	// Test for only allowing headers_only for framework-minus-apex-headers
+	{
+		name: `"headers_only" outside framework-minus-apex-headers modules`,
+		fs: map[string][]byte{
+			"a/b/Android.bp": []byte(`
+				java_library {
+					name: "baz",
+					headers_only: true,
+				}
+			`),
+		},
+		expectedErrors: []string{
+			`headers_only can only be used for generating framework-minus-apex headers for non-updatable modules`,
+		},
+	},
 }
 
 var prepareForNeverAllowTest = GroupFixturePreparers(
@@ -451,6 +466,7 @@
 	Sdk_version         *string
 	Uncompress_dex      *bool
 	Exclude_static_libs []string
+	Headers_only        *bool
 }
 
 type mockJavaLibraryModule struct {
diff --git a/android/override_module.go b/android/override_module.go
index a4b7431..9e0de6f 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -353,26 +353,26 @@
 // variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
 // or if this variant is not overridden.
 func ModuleNameWithPossibleOverride(ctx BazelConversionContext) string {
-	return moduleNameWithPossibleOverride(ctx, ctx.Module())
+	return moduleNameWithPossibleOverride(ctx, ctx.Module(), ctx.OtherModuleName(ctx.Module()))
 }
 
-func moduleNameWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
+func moduleNameWithPossibleOverride(ctx shouldConvertModuleContext, module blueprint.Module, name string) string {
 	if overridable, ok := module.(OverridableModule); ok {
 		if o := overridable.GetOverriddenBy(); o != "" {
 			return o
 		}
 	}
-	return ctx.OtherModuleName(module)
+	return name
 }
 
 // moduleDirWithPossibleOverride returns the dir of the OverrideModule that overrides the current
 // variant of the given OverridableModule, or ctx.OtherModuleName() if the module is not an
 // OverridableModule or if the variant is not overridden.
-func moduleDirWithPossibleOverride(ctx bazelOtherModuleContext, module blueprint.Module) string {
+func moduleDirWithPossibleOverride(ctx shouldConvertModuleContext, module blueprint.Module, dir string) string {
 	if overridable, ok := module.(OverridableModule); ok {
 		if o := overridable.GetOverriddenByModuleDir(); o != "" {
 			return o
 		}
 	}
-	return ctx.OtherModuleDir(module)
+	return dir
 }
diff --git a/android/paths.go b/android/paths.go
index e16cb37..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1029,16 +1029,16 @@
 	return p
 }
 
+func (p basePath) RelativeToTop() Path {
+	ensureTestOnly()
+	return p
+}
+
 // SourcePath is a Path representing a file path rooted from SrcDir
 type SourcePath struct {
 	basePath
 }
 
-func (p SourcePath) RelativeToTop() Path {
-	ensureTestOnly()
-	return p
-}
-
 var _ Path = SourcePath{}
 
 func (p SourcePath) withRel(rel string) SourcePath {
@@ -1126,6 +1126,16 @@
 	return path
 }
 
+// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
+// the path is relative to the root of the output folder, not the out/soong folder.
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
+	p, err := validatePath(pathComponents...)
+	if err != nil {
+		reportPathError(ctx, err)
+	}
+	return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+}
+
 // MaybeExistentPathForSource joins the provided path components and validates that the result
 // neither escapes the source dir nor is in the out dir.
 // It does not validate whether the path exists.
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index e5edf91..aeae20f 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -102,6 +102,10 @@
 // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
 // in genrules with the "tools" property.
 func prebuiltBuildToolFactory() Module {
+	return NewPrebuiltBuildTool()
+}
+
+func NewPrebuiltBuildTool() Module {
 	module := &prebuiltBuildTool{}
 	module.AddProperties(&module.properties)
 	InitSingleSourcePrebuiltModule(module, &module.properties, "Src")
diff --git a/android/proto.go b/android/proto.go
index cebbd59..fc21d01 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -15,7 +15,9 @@
 package android
 
 import (
+	"path/filepath"
 	"strings"
+	"sync"
 
 	"android/soong/bazel"
 
@@ -155,13 +157,14 @@
 
 // Bp2buildProtoInfo contains information necessary to pass on to language specific conversion.
 type Bp2buildProtoInfo struct {
-	Type       *string
-	Name       string
-	Proto_libs bazel.LabelList
+	Type                  *string
+	Proto_libs            bazel.LabelList
+	Transitive_proto_libs bazel.LabelList
 }
 
 type ProtoAttrs struct {
 	Srcs                bazel.LabelListAttribute
+	Import_prefix       *string
 	Strip_import_prefix *string
 	Deps                bazel.LabelListAttribute
 }
@@ -172,6 +175,35 @@
 	"external/protobuf/src": "//external/protobuf:libprotobuf-proto",
 }
 
+// Partitions srcs by the pkg it is in
+// srcs has been created using `TransformSubpackagePaths`
+// This function uses existence of Android.bp/BUILD files to create a label that is compatible with the package structure of bp2build workspace
+func partitionSrcsByPackage(currentDir string, srcs bazel.LabelList) map[string]bazel.LabelList {
+	getPackageFromLabel := func(label string) string {
+		// Remove any preceding //
+		label = strings.TrimPrefix(label, "//")
+		split := strings.Split(label, ":")
+		if len(split) == 1 {
+			// e.g. foo.proto
+			return currentDir
+		} else if split[0] == "" {
+			// e.g. :foo.proto
+			return currentDir
+		} else {
+			return split[0]
+		}
+	}
+
+	pkgToSrcs := map[string]bazel.LabelList{}
+	for _, src := range srcs.Includes {
+		pkg := getPackageFromLabel(src.Label)
+		list := pkgToSrcs[pkg]
+		list.Add(&src)
+		pkgToSrcs[pkg] = list
+	}
+	return pkgToSrcs
+}
+
 // Bp2buildProtoProperties converts proto properties, creating a proto_library and returning the
 // information necessary for language-specific handling.
 func Bp2buildProtoProperties(ctx Bp2buildMutatorContext, m *ModuleBase, srcs bazel.LabelListAttribute) (Bp2buildProtoInfo, bool) {
@@ -181,6 +213,7 @@
 	}
 
 	var protoLibraries bazel.LabelList
+	var transitiveProtoLibraries bazel.LabelList
 	var directProtoSrcs bazel.LabelList
 
 	// For filegroups that should be converted to proto_library just collect the
@@ -197,57 +230,202 @@
 		}
 	}
 
-	info.Name = m.Name() + "_proto"
+	name := m.Name() + "_proto"
+
+	depsFromFilegroup := protoLibraries
+	var canonicalPathFromRoot bool
 
 	if len(directProtoSrcs.Includes) > 0 {
-		attrs := ProtoAttrs{
-			Srcs: bazel.MakeLabelListAttribute(directProtoSrcs),
-		}
-		attrs.Deps.Append(bazel.MakeLabelListAttribute(protoLibraries))
+		pkgToSrcs := partitionSrcsByPackage(ctx.ModuleDir(), directProtoSrcs)
+		protoIncludeDirs := []string{}
+		for _, pkg := range SortedStringKeys(pkgToSrcs) {
+			srcs := pkgToSrcs[pkg]
+			attrs := ProtoAttrs{
+				Srcs: bazel.MakeLabelListAttribute(srcs),
+			}
+			attrs.Deps.Append(bazel.MakeLabelListAttribute(depsFromFilegroup))
 
-		for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
-			for _, rawProps := range configToProps {
-				var props *ProtoProperties
-				var ok bool
-				if props, ok = rawProps.(*ProtoProperties); !ok {
-					ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
-				}
-				if axis == bazel.NoConfigAxis {
-					info.Type = props.Proto.Type
-
-					if !proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault) {
-						// an empty string indicates to strips the package path
-						path := ""
-						attrs.Strip_import_prefix = &path
+			for axis, configToProps := range m.GetArchVariantProperties(ctx, &ProtoProperties{}) {
+				for _, rawProps := range configToProps {
+					var props *ProtoProperties
+					var ok bool
+					if props, ok = rawProps.(*ProtoProperties); !ok {
+						ctx.ModuleErrorf("Could not cast ProtoProperties to expected type")
 					}
+					if axis == bazel.NoConfigAxis {
+						info.Type = props.Proto.Type
 
-					for _, dir := range props.Proto.Include_dirs {
-						if dep, ok := includeDirsToProtoDeps[dir]; ok {
-							attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
-						} else {
-							ctx.PropertyErrorf("Could not find the proto_library target for include dir", dir)
+						canonicalPathFromRoot = proptools.BoolDefault(props.Proto.Canonical_path_from_root, canonicalPathFromRootDefault)
+						if !canonicalPathFromRoot {
+							// an empty string indicates to strips the package path
+							path := ""
+							attrs.Strip_import_prefix = &path
 						}
+
+						for _, dir := range props.Proto.Include_dirs {
+							if dep, ok := includeDirsToProtoDeps[dir]; ok {
+								attrs.Deps.Add(bazel.MakeLabelAttribute(dep))
+							} else {
+								protoIncludeDirs = append(protoIncludeDirs, dir)
+							}
+						}
+
+						// proto.local_include_dirs are similar to proto.include_dirs, except that it is relative to the module directory
+						for _, dir := range props.Proto.Local_include_dirs {
+							relativeToTop := pathForModuleSrc(ctx, dir).String()
+							protoIncludeDirs = append(protoIncludeDirs, relativeToTop)
+						}
+
+					} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
+						ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
 					}
-				} else if props.Proto.Type != info.Type && props.Proto.Type != nil {
-					ctx.ModuleErrorf("Cannot handle arch-variant types for protos at this time.")
 				}
 			}
+
+			if p, ok := m.module.(PkgPathInterface); ok && p.PkgPath(ctx) != nil {
+				// python_library with pkg_path
+				// proto_library for this module should have the pkg_path as the import_prefix
+				attrs.Import_prefix = p.PkgPath(ctx)
+				attrs.Strip_import_prefix = proptools.StringPtr("")
+			}
+
+			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
+
+			moduleDir := ctx.ModuleDir()
+			if !canonicalPathFromRoot {
+				// Since we are creating the proto_library in a subpackage, set the import_prefix relative to the current package
+				if rel, err := filepath.Rel(moduleDir, pkg); err != nil {
+					ctx.ModuleErrorf("Could not get relative path for %v %v", pkg, err)
+				} else if rel != "." {
+					attrs.Import_prefix = &rel
+				}
+			}
+
+			// TODO - b/246997908: Handle potential orphaned proto_library targets
+			// To create proto_library targets in the same package, we split the .proto files
+			// This means that if a proto_library in a subpackage imports another proto_library from the parent package
+			// (or a different subpackage), it will not find it.
+			// The CcProtoGen action itself runs fine because we construct the correct ProtoInfo,
+			// but the FileDescriptorSet of each proto_library might not be compile-able
+			//
+			// Add manual tag if either
+			// 1. .proto files are in more than one package
+			// 2. proto.include_dirs is not empty
+			if len(SortedStringKeys(pkgToSrcs)) > 1 || len(protoIncludeDirs) > 0 {
+				tags.Append(bazel.MakeStringListAttribute([]string{"manual"}))
+			}
+
+			ctx.CreateBazelTargetModule(
+				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+				CommonAttributes{Name: name, Dir: proptools.StringPtr(pkg), Tags: tags},
+				&attrs,
+			)
+
+			l := ""
+			if pkg == moduleDir { // same package that the original module lives in
+				l = ":" + name
+			} else {
+				l = "//" + pkg + ":" + name
+			}
+			protoLibraries.Add(&bazel.Label{
+				Label: l,
+			})
 		}
-
-		tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
-
-		ctx.CreateBazelTargetModule(
-			bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
-			CommonAttributes{Name: info.Name, Tags: tags},
-			&attrs,
-		)
-
-		protoLibraries.Add(&bazel.Label{
-			Label: ":" + info.Name,
-		})
+		// Partitioning by packages can create dupes of protoIncludeDirs, so dedupe it first.
+		protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, SortedUniqueStrings(protoIncludeDirs))
+		transitiveProtoLibraries.Append(protoLibrariesInIncludeDir)
 	}
 
 	info.Proto_libs = protoLibraries
+	info.Transitive_proto_libs = transitiveProtoLibraries
 
 	return info, true
 }
+
+// PkgPathInterface is used as a type assertion in bp2build to get pkg_path property of python_library_host
+type PkgPathInterface interface {
+	PkgPath(ctx BazelConversionContext) *string
+}
+
+var (
+	protoIncludeDirGeneratedSuffix = ".include_dir_bp2build_generated_proto"
+	protoIncludeDirsBp2buildKey    = NewOnceKey("protoIncludeDirsBp2build")
+)
+
+func getProtoIncludeDirsBp2build(config Config) *sync.Map {
+	return config.Once(protoIncludeDirsBp2buildKey, func() interface{} {
+		return &sync.Map{}
+	}).(*sync.Map)
+}
+
+// key for dynamically creating proto_library per proto.include_dirs
+type protoIncludeDirKey struct {
+	dir            string
+	subpackgeInDir string
+}
+
+// createProtoLibraryTargetsForIncludeDirs creates additional proto_library targets for .proto files in includeDirs
+// Since Bazel imposes a constratint that the proto_library must be in the same package as the .proto file, this function
+// might create the targets in a subdirectory of `includeDir`
+// Returns the labels of the proto_library targets
+func createProtoLibraryTargetsForIncludeDirs(ctx Bp2buildMutatorContext, includeDirs []string) bazel.LabelList {
+	var ret bazel.LabelList
+	for _, dir := range includeDirs {
+		if exists, _, _ := ctx.Config().fs.Exists(filepath.Join(dir, "Android.bp")); !exists {
+			ctx.ModuleErrorf("TODO: Add support for proto.include_dir: %v. This directory does not contain an Android.bp file", dir)
+		}
+		dirMap := getProtoIncludeDirsBp2build(ctx.Config())
+		// Find all proto file targets in this dir
+		protoLabelsInDir := BazelLabelForSrcPatternExcludes(ctx, dir, "**/*.proto", []string{})
+		// Partition the labels by package and subpackage(s)
+		protoLabelelsPartitionedByPkg := partitionSrcsByPackage(dir, protoLabelsInDir)
+		for _, pkg := range SortedStringKeys(protoLabelelsPartitionedByPkg) {
+			label := strings.ReplaceAll(dir, "/", ".") + protoIncludeDirGeneratedSuffix
+			ret.Add(&bazel.Label{
+				Label: "//" + pkg + ":" + label,
+			})
+			key := protoIncludeDirKey{dir: dir, subpackgeInDir: pkg}
+			if _, exists := dirMap.LoadOrStore(key, true); exists {
+				// A proto_library has already been created for this package relative to this include dir
+				continue
+			}
+			srcs := protoLabelelsPartitionedByPkg[pkg]
+			rel, err := filepath.Rel(dir, pkg)
+			if err != nil {
+				ctx.ModuleErrorf("Could not create a proto_library in pkg %v due to %v\n", pkg, err)
+			}
+			// Create proto_library
+			attrs := ProtoAttrs{
+				Srcs:                bazel.MakeLabelListAttribute(srcs),
+				Strip_import_prefix: proptools.StringPtr(""),
+			}
+			if rel != "." {
+				attrs.Import_prefix = proptools.StringPtr(rel)
+			}
+
+			// If a specific directory is listed in proto.include_dirs of two separate modules (one host-specific and another device-specific),
+			// we do not want to create the proto_library with target_compatible_with of the first visited of these two modules
+			// As a workarounds, delete `target_compatible_with`
+			alwaysEnabled := bazel.BoolAttribute{}
+			alwaysEnabled.Value = proptools.BoolPtr(true)
+			// Add android and linux explicitly so that fillcommonbp2buildmoduleattrs can override these configs
+			// When we extend b support for other os'es (darwin/windows), we should add those configs here as well
+			alwaysEnabled.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid, proptools.BoolPtr(true))
+			alwaysEnabled.SetSelectValue(bazel.OsConfigurationAxis, bazel.OsLinux, proptools.BoolPtr(true))
+
+			ctx.CreateBazelTargetModuleWithRestrictions(
+				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
+				CommonAttributes{
+					Name: label,
+					Dir:  proptools.StringPtr(pkg),
+					// This proto_library is used to construct a ProtoInfo
+					// But it might not be buildable on its own
+					Tags: bazel.MakeStringListAttribute([]string{"manual"}),
+				},
+				&attrs,
+				alwaysEnabled,
+			)
+		}
+	}
+	return ret
+}
diff --git a/android/register.go b/android/register.go
index 64b0207..df97c75 100644
--- a/android/register.go
+++ b/android/register.go
@@ -197,13 +197,6 @@
 	RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
 }
 
-// RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that
-// it only generates API targets in the generated  workspace
-func (ctx *Context) RegisterForApiBazelConversion() {
-	registerModuleTypes(ctx)
-	RegisterMutatorsForApiBazelConversion(ctx, bp2buildPreArchMutators)
-}
-
 // Register the pipeline of singletons, module types, and mutators for
 // generating build.ninja and other files for Kati, from Android.bp files.
 func (ctx *Context) Register() {
diff --git a/android/testing.go b/android/testing.go
index 5ad7ad0..32357db 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -467,12 +467,6 @@
 	RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
 }
 
-// RegisterForApiBazelConversion prepares a test context for API bp2build conversion.
-func (ctx *TestContext) RegisterForApiBazelConversion() {
-	ctx.config.BuildMode = ApiBp2build
-	RegisterMutatorsForApiBazelConversion(ctx.Context, ctx.bp2buildPreArch)
-}
-
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
 	// This function adapts the old style ParseFileList calls that are spread throughout the tests
 	// to the new style that takes a config.
diff --git a/android/variable.go b/android/variable.go
index f07ab56..524cdf7 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -95,10 +95,6 @@
 			Cflags []string
 		}
 
-		Device_page_size_agnostic struct {
-			Cflags []string `android:"arch_variant"`
-		} `android:"arch_variant"`
-
 		Override_rs_driver struct {
 			Cflags []string
 		}
@@ -142,6 +138,7 @@
 
 			Srcs         []string
 			Exclude_srcs []string
+			Cmd          *string
 		}
 
 		// eng is true for -eng builds, and can be used to turn on additional heavyweight debugging
@@ -160,10 +157,6 @@
 			}
 		}
 
-		Pdk struct {
-			Enabled *bool `android:"arch_variant"`
-		} `android:"arch_variant"`
-
 		Uml struct {
 			Cppflags []string
 		}
@@ -184,6 +177,13 @@
 			Srcs         []string `android:"arch_variant"`
 			Exclude_srcs []string `android:"arch_variant"`
 		} `android:"arch_variant"`
+
+		// release_aidl_use_unfrozen is "true" when a device can
+		// use the unfrozen versions of AIDL interfaces.
+		Release_aidl_use_unfrozen struct {
+			Cflags []string
+			Cmd    *string
+		}
 	} `android:"arch_variant"`
 }
 
@@ -224,6 +224,7 @@
 	DeviceCurrentApiLevelForVendorModules *string  `json:",omitempty"`
 	DeviceSystemSdkVersions               []string `json:",omitempty"`
 	DeviceMaxPageSizeSupported            *string  `json:",omitempty"`
+	DevicePageSizeAgnostic                *bool    `json:",omitempty"`
 
 	RecoverySnapshotVersion *string `json:",omitempty"`
 
@@ -279,7 +280,6 @@
 	Safestack                    *bool    `json:",omitempty"`
 	HostStaticBinaries           *bool    `json:",omitempty"`
 	Binder32bit                  *bool    `json:",omitempty"`
-	Device_page_size_agnostic    *bool    `json:",omitempty"`
 	UseGoma                      *bool    `json:",omitempty"`
 	UseRBE                       *bool    `json:",omitempty"`
 	UseRBEJAVAC                  *bool    `json:",omitempty"`
@@ -315,6 +315,7 @@
 	MemtagHeapSyncIncludePaths  []string `json:",omitempty"`
 
 	HWASanIncludePaths []string `json:",omitempty"`
+	HWASanExcludePaths []string `json:",omitempty"`
 
 	VendorPath    *string `json:",omitempty"`
 	OdmPath       *string `json:",omitempty"`
@@ -372,17 +373,11 @@
 
 	MultitreeUpdateMeta bool `json:",omitempty"`
 
-	BoardVendorSepolicyDirs           []string `json:",omitempty"`
-	BoardOdmSepolicyDirs              []string `json:",omitempty"`
-	BoardReqdMaskPolicy               []string `json:",omitempty"`
-	BoardPlatVendorPolicy             []string `json:",omitempty"`
-	BoardSystemExtPublicPrebuiltDirs  []string `json:",omitempty"`
-	BoardSystemExtPrivatePrebuiltDirs []string `json:",omitempty"`
-	BoardProductPublicPrebuiltDirs    []string `json:",omitempty"`
-	BoardProductPrivatePrebuiltDirs   []string `json:",omitempty"`
-	SystemExtPublicSepolicyDirs       []string `json:",omitempty"`
-	SystemExtPrivateSepolicyDirs      []string `json:",omitempty"`
-	BoardSepolicyM4Defs               []string `json:",omitempty"`
+	BoardVendorSepolicyDirs      []string `json:",omitempty"`
+	BoardOdmSepolicyDirs         []string `json:",omitempty"`
+	SystemExtPublicSepolicyDirs  []string `json:",omitempty"`
+	SystemExtPrivateSepolicyDirs []string `json:",omitempty"`
+	BoardSepolicyM4Defs          []string `json:",omitempty"`
 
 	BoardSepolicyVers       *string `json:",omitempty"`
 	PlatformSepolicyVersion *string `json:",omitempty"`
@@ -443,16 +438,17 @@
 
 	ShippingApiLevel *string `json:",omitempty"`
 
-	BuildBrokenPluginValidation        []string `json:",omitempty"`
-	BuildBrokenClangAsFlags            bool     `json:",omitempty"`
-	BuildBrokenClangCFlags             bool     `json:",omitempty"`
-	BuildBrokenClangProperty           bool     `json:",omitempty"`
-	GenruleSandboxing                  *bool    `json:",omitempty"`
-	BuildBrokenEnforceSyspropOwner     bool     `json:",omitempty"`
-	BuildBrokenTrebleSyspropNeverallow bool     `json:",omitempty"`
-	BuildBrokenUsesSoongPython2Modules bool     `json:",omitempty"`
-	BuildBrokenVendorPropertyNamespace bool     `json:",omitempty"`
-	BuildBrokenInputDirModules         []string `json:",omitempty"`
+	BuildBrokenPluginValidation         []string `json:",omitempty"`
+	BuildBrokenClangAsFlags             bool     `json:",omitempty"`
+	BuildBrokenClangCFlags              bool     `json:",omitempty"`
+	BuildBrokenClangProperty            bool     `json:",omitempty"`
+	GenruleSandboxing                   *bool    `json:",omitempty"`
+	BuildBrokenEnforceSyspropOwner      bool     `json:",omitempty"`
+	BuildBrokenTrebleSyspropNeverallow  bool     `json:",omitempty"`
+	BuildBrokenUsesSoongPython2Modules  bool     `json:",omitempty"`
+	BuildBrokenVendorPropertyNamespace  bool     `json:",omitempty"`
+	BuildBrokenIncorrectPartitionImages bool     `json:",omitempty"`
+	BuildBrokenInputDirModules          []string `json:",omitempty"`
 
 	BuildWarningBadOptionalUsesLibsAllowlist []string `json:",omitempty"`
 
@@ -462,6 +458,8 @@
 
 	SelinuxIgnoreNeverallows bool `json:",omitempty"`
 
+	Release_aidl_use_unfrozen *bool `json:",omitempty"`
+
 	SepolicyFreezeTestExtraDirs         []string `json:",omitempty"`
 	SepolicyFreezeTestExtraPrebuiltDirs []string `json:",omitempty"`
 
@@ -481,7 +479,11 @@
 	ReleaseVersion          string   `json:",omitempty"`
 	ReleaseAconfigValueSets []string `json:",omitempty"`
 
+	ReleaseAconfigFlagDefaultPermission string `json:",omitempty"`
+
 	KeepVndk *bool `json:",omitempty"`
+
+	CheckVendorSeappViolations *bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
@@ -522,6 +524,7 @@
 		DeviceSecondaryCpuVariant:  stringPtr("generic"),
 		DeviceSecondaryAbi:         []string{"armeabi-v7a", "armeabi"},
 		DeviceMaxPageSizeSupported: stringPtr("4096"),
+		DevicePageSizeAgnostic:     boolPtr(false),
 
 		AAPTConfig:          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 		AAPTPreferredConfig: stringPtr("xhdpi"),
@@ -534,7 +537,6 @@
 		Safestack:                    boolPtr(false),
 		TrimmedApex:                  boolPtr(false),
 		Build_from_text_stub:         boolPtr(false),
-		Device_page_size_agnostic:    boolPtr(false),
 
 		BootJars:     ConfiguredJarList{apexes: []string{}, jars: []string{}},
 		ApexBootJars: ConfiguredJarList{apexes: []string{}, jars: []string{}},
@@ -674,11 +676,16 @@
 
 	if moduleBase.variableProperties != nil {
 		productVariablesProperty := proptools.FieldNameForProperty("product_variables")
-		for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
-			for config, props := range configToProps {
-				variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty)
-				productConfigProperties.AddProductConfigProperties(variableValues, config)
+		if moduleBase.ArchSpecific() {
+			for /* axis */ _, configToProps := range moduleBase.GetArchVariantProperties(ctx, moduleBase.variableProperties) {
+				for config, props := range configToProps {
+					variableValues := reflect.ValueOf(props).Elem().FieldByName(productVariablesProperty)
+					productConfigProperties.AddProductConfigProperties(variableValues, config)
+				}
 			}
+		} else {
+			variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName(productVariablesProperty)
+			productConfigProperties.AddProductConfigProperties(variableValues, "")
 		}
 	}
 
@@ -734,7 +741,9 @@
 			dst = append(dst, src...)
 			(*p)[propertyName][key] = dst
 		default:
-			panic(fmt.Errorf("TODO: handle merging value %#v", existing))
+			if existing != propertyValue {
+				panic(fmt.Errorf("TODO: handle merging value %#v", existing))
+			}
 		}
 	} else {
 		(*p)[propertyName][key] = propertyValue
@@ -947,7 +956,7 @@
 						productConfigProperties.AddSoongConfigProperty(propertyName, namespace, soongConfigVariableName, soongConfigVariableValue, os.Name, property.Interface())
 					}
 				}
-			} else {
+			} else if !archOrOsSpecificStruct.IsZero() {
 				// One problem with supporting additional fields is that if multiple branches of
 				// "target" overlap, we don't want them to be in the same select statement (aka
 				// configuration axis). "android" and "host" are disjoint, so it's ok that we only
diff --git a/apex/androidmk.go b/apex/androidmk.go
index f469062..2f5d8d4 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -42,7 +42,7 @@
 		return "ETC"
 	case nativeSharedLib:
 		return "SHARED_LIBRARIES"
-	case nativeExecutable, shBinary, pyBinary, goBinary:
+	case nativeExecutable, shBinary:
 		return "EXECUTABLES"
 	case javaSharedLib:
 		return "JAVA_LIBRARIES"
@@ -67,7 +67,7 @@
 	if linkToSystemLib {
 		return fi.androidMkModuleName
 	}
-	return fi.androidMkModuleName + "." + apexBundleName + a.suffix
+	return fi.androidMkModuleName + "." + apexBundleName
 }
 
 // androidMkForFiles generates Make definitions for the contents of an
@@ -85,11 +85,6 @@
 	// conflicts between two apexes with the same apexName.
 
 	moduleNames := []string{}
-	// To avoid creating duplicate build rules, run this function only when primaryApexType is true
-	// to install symbol files in $(PRODUCT_OUT}/apex.
-	if !a.primaryApexType {
-		return moduleNames
-	}
 
 	for _, fi := range a.filesInfo {
 		linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform()
@@ -140,32 +135,9 @@
 		fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake())
 		if fi.module != nil {
 			// This apexFile's module comes from Soong
-			archStr := fi.module.Target().Arch.ArchType.String()
-			host := false
-			switch fi.module.Target().Os.Class {
-			case android.Host:
-				if fi.module.Target().HostCross {
-					if fi.module.Target().Arch.ArchType != android.Common {
-						fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
-					}
-				} else {
-					if fi.module.Target().Arch.ArchType != android.Common {
-						fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
-					}
-				}
-				host = true
-			case android.Device:
-				if fi.module.Target().Arch.ArchType != android.Common {
-					fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
-				}
-			}
-			if host {
-				makeOs := fi.module.Target().Os.String()
-				if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic || fi.module.Target().Os == android.LinuxMusl {
-					makeOs = "linux"
-				}
-				fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+			if fi.module.Target().Arch.ArchType != android.Common {
+				archStr := fi.module.Target().Arch.ArchType.String()
+				fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
 			}
 		} else if fi.isBazelPrebuilt && fi.arch != "" {
 			// This apexFile comes from Bazel
@@ -237,7 +209,7 @@
 		}
 
 		// m <module_name> will build <module_name>.<apex_name> as well.
-		if fi.androidMkModuleName != moduleName && a.primaryApexType {
+		if fi.androidMkModuleName != moduleName {
 			fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
 			fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
 		}
@@ -266,19 +238,18 @@
 	return android.AndroidMkData{
 		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
 			moduleNames := []string{}
-			apexType := a.properties.ApexType
 			if a.installable() {
 				moduleNames = a.androidMkForFiles(w, name, moduleDir, data)
 			}
 
 			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)  # apex.apexBundle")
 			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-			fmt.Fprintln(w, "LOCAL_MODULE :=", name+a.suffix)
+			fmt.Fprintln(w, "LOCAL_MODULE :=", name)
 			data.Entries.WriteLicenseVariables(w)
 			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
 			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.String())
-			stemSuffix := apexType.suffix()
+			stemSuffix := imageApexSuffix
 			if a.isCompressed {
 				stemSuffix = imageCapexSuffix
 			}
@@ -287,6 +258,7 @@
 			if a.installable() {
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
 				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_SYMLINKS := ", strings.Join(a.compatSymlinks.Strings(), " "))
 			}
 
 			// Because apex writes .mk with Custom(), we need to write manually some common properties
@@ -306,10 +278,7 @@
 			a.writeRequiredModules(w, moduleNames)
 
 			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
-
-			if apexType == imageApex {
-				fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
-			}
+			fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
 			android.AndroidMkEmitAssignList(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS", a.lintReports.Strings())
 
 			if a.installedFilesFile != nil {
diff --git a/apex/apex.go b/apex/apex.go
index 325ca00..a116b85 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -18,6 +18,7 @@
 
 import (
 	"fmt"
+	"log"
 	"path/filepath"
 	"regexp"
 	"sort"
@@ -26,7 +27,6 @@
 	"android/soong/bazel/cquery"
 
 	"github.com/google/blueprint"
-	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -37,7 +37,6 @@
 	"android/soong/filesystem"
 	"android/soong/java"
 	"android/soong/multitree"
-	"android/soong/python"
 	"android/soong/rust"
 	"android/soong/sh"
 )
@@ -79,7 +78,6 @@
 	ctx.BottomUp("mark_platform_availability", markPlatformAvailability).Parallel()
 	ctx.BottomUp("apex", apexMutator).Parallel()
 	ctx.BottomUp("apex_directly_in_any", apexDirectlyInAnyMutator).Parallel()
-	ctx.BottomUp("apex_packaging", apexPackagingMutator).Parallel()
 	ctx.BottomUp("apex_dcla_deps", apexDCLADepsMutator).Parallel()
 	// Register after apex_info mutator so that it can use ApexVariationName
 	ctx.TopDown("apex_strict_updatability_lint", apexStrictUpdatibilityLintMutator).Parallel()
@@ -166,15 +164,7 @@
 	// Should be only used in non-system apexes (e.g. vendor: true). Default is false.
 	Use_vndk_as_stable *bool
 
-	// The type of APEX to build. Controls what the APEX payload is. Either 'image', 'zip' or
-	// 'both'. When set to image, contents are stored in a filesystem image inside a zip
-	// container. When set to zip, contents are stored in a zip container directly. This type is
-	// mostly for host-side debugging. When set to both, the two types are both built. Default
-	// is 'image'.
-	Payload_type *string
-
-	// The type of filesystem to use when the payload_type is 'image'. Either 'ext4', 'f2fs'
-	// or 'erofs'. Default 'ext4'.
+	// The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'.
 	Payload_fs_type *string
 
 	// For telling the APEX to ignore special handling for system libraries such as bionic.
@@ -216,9 +206,6 @@
 
 	HideFromMake bool `blueprint:"mutated"`
 
-	// Internal package method for this APEX.
-	ApexType apexPackaging `blueprint:"mutated"`
-
 	// Name that dependencies can specify in their apex_available properties to refer to this module.
 	// If not specified, this defaults to Soong module name. This must be the name of a Soong module.
 	Apex_available_name *string
@@ -421,13 +408,6 @@
 	testApex bool
 	vndkApex bool
 
-	// Tells whether this variant of the APEX bundle is the primary one or not. Only the primary
-	// one gets installed to the device.
-	primaryApexType bool
-
-	// Suffix of module name in Android.mk ".apex", ".zipapex", or ""
-	suffix string
-
 	// File system type of apex_payload.img
 	payloadFsType fsType
 
@@ -506,12 +486,10 @@
 	app apexFileClass = iota
 	appSet
 	etc
-	goBinary
 	javaSharedLib
 	nativeExecutable
 	nativeSharedLib
 	nativeTest
-	pyBinary
 	shBinary
 )
 
@@ -520,12 +498,10 @@
 		"app":              app,
 		"appSet":           appSet,
 		"etc":              etc,
-		"goBinary":         goBinary,
 		"javaSharedLib":    javaSharedLib,
 		"nativeExecutable": nativeExecutable,
 		"nativeSharedLib":  nativeSharedLib,
 		"nativeTest":       nativeTest,
-		"pyBinary":         pyBinary,
 		"shBinary":         shBinary,
 	}
 )
@@ -716,11 +692,10 @@
 	libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
 	rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"})
 
-	if ctx.Device() {
-		binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-		rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
-	}
+	// Append "image" variation
+	binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+	libVariations = append(libVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
+	rustLibVariations = append(rustLibVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
 
 	// Use *FarVariation* to be able to depend on modules having conflicting variations with
 	// this module. This is required since arch variant of an APEX bundle is 'common' but it is
@@ -740,16 +715,7 @@
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
-	if ctx.Device() {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
-	} else {
-		proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Host.Multilib, nil)
-		if ctx.Os().Bionic() {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_bionic.Multilib, nil)
-		} else {
-			proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Linux_glibc.Multilib, nil)
-		}
-	}
+	proptools.AppendProperties(&a.properties.Multilib, &a.targetProperties.Target.Android.Multilib, nil)
 }
 
 // getImageVariationPair returns a pair for the image variation name as its
@@ -807,12 +773,6 @@
 		}
 	}
 	for i, target := range targets {
-		// Don't include artifacts for the host cross targets because there is no way for us
-		// to run those artifacts natively on host
-		if target.HostCross {
-			continue
-		}
-
 		var deps ApexNativeDependencies
 
 		// Add native modules targeting both ABIs. When multilib.* is omitted for
@@ -993,7 +953,7 @@
 	// the non-system APEXes because the VNDK libraries won't be included (and duped) in the
 	// APEX, but shared across APEXes via the VNDK APEX.
 	useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
-	excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
+	excludeVndkLibs := useVndk && a.useVndkAsStable(mctx)
 	if proptools.Bool(a.properties.Use_vndk_as_stable) {
 		if !useVndk {
 			mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
@@ -1032,6 +992,13 @@
 				return false
 			}
 		}
+
+		//TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated.
+		if useVndk && mctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" {
+			log.Print("Libbinder is linked from Vendor APEX ", a.Name(), " with module ", parent.Name())
+			return false
+		}
+
 		// By default, all the transitive dependencies are collected, unless filtered out
 		// above.
 		return true
@@ -1249,8 +1216,8 @@
 // be) available to platform
 // TODO(jiyong): move this to android/apex.go?
 func markPlatformAvailability(mctx android.BottomUpMutatorContext) {
-	// Host and recovery are not considered as platform
-	if mctx.Host() || mctx.Module().InstallInRecovery() {
+	// Recovery is not considered as platform
+	if mctx.Module().InstallInRecovery() {
 		return
 	}
 
@@ -1353,95 +1320,19 @@
 	}
 }
 
-// apexPackaging represents a specific packaging method for an APEX.
-type apexPackaging int
-
-const (
-	// imageApex is a packaging method where contents are included in a filesystem image which
-	// is then included in a zip container. This is the most typical way of packaging.
-	imageApex apexPackaging = iota
-
-	// zipApex is a packaging method where contents are directly included in the zip container.
-	// This is used for host-side testing - because the contents are easily accessible by
-	// unzipping the container.
-	// TODO(b/279835185) deprecate zipApex
-	zipApex
-)
-
 const (
 	// File extensions of an APEX for different packaging methods
 	imageApexSuffix  = ".apex"
 	imageCapexSuffix = ".capex"
-	zipApexSuffix    = ".zipapex"
 
 	// variant names each of which is for a packaging method
 	imageApexType = "image"
-	zipApexType   = "zip"
 
 	ext4FsType  = "ext4"
 	f2fsFsType  = "f2fs"
 	erofsFsType = "erofs"
 )
 
-// The suffix for the output "file", not the module
-func (a apexPackaging) suffix() string {
-	switch a {
-	case imageApex:
-		return imageApexSuffix
-	case zipApex:
-		return zipApexSuffix
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-func (a apexPackaging) name() string {
-	switch a {
-	case imageApex:
-		return imageApexType
-	case zipApex:
-		return zipApexType
-	default:
-		panic(fmt.Errorf("unknown APEX type %d", a))
-	}
-}
-
-// apexPackagingMutator creates one or more variations each of which is for a packaging method.
-func apexPackagingMutator(mctx android.BottomUpMutatorContext) {
-	if !mctx.Module().Enabled() {
-		return
-	}
-	if ab, ok := mctx.Module().(*apexBundle); ok {
-		var variants []string
-		switch proptools.StringDefault(ab.properties.Payload_type, "image") {
-		case "image":
-			variants = append(variants, imageApexType)
-		case "zip":
-			variants = append(variants, zipApexType)
-		case "both":
-			variants = append(variants, imageApexType, zipApexType)
-		default:
-			mctx.PropertyErrorf("payload_type", "%q is not one of \"image\", \"zip\", or \"both\".", *ab.properties.Payload_type)
-			return
-		}
-
-		modules := mctx.CreateLocalVariations(variants...)
-
-		for i, v := range variants {
-			switch v {
-			case imageApexType:
-				modules[i].(*apexBundle).properties.ApexType = imageApex
-			case zipApexType:
-				modules[i].(*apexBundle).properties.ApexType = zipApex
-			}
-		}
-	} else if _, ok := mctx.Module().(*OverrideApex); ok {
-		// payload_type is forcibly overridden to "image"
-		// TODO(jiyong): is this the right decision?
-		mctx.CreateVariations(imageApexType)
-	}
-}
-
 var _ android.DepIsInSameApex = (*apexBundle)(nil)
 
 // Implements android.DepInInSameApex
@@ -1486,7 +1377,7 @@
 
 // Implements cc.Coverage
 func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
-	return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
+	return ctx.DeviceConfig().NativeCoverageEnabled()
 }
 
 // Implements cc.Coverage
@@ -1597,13 +1488,9 @@
 
 	// Then follow the global setting
 	var globalSanitizerNames []string
-	if a.Host() {
-		globalSanitizerNames = config.SanitizeHost()
-	} else {
-		arches := config.SanitizeDeviceArch()
-		if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) {
-			globalSanitizerNames = config.SanitizeDevice()
-		}
+	arches := config.SanitizeDeviceArch()
+	if len(arches) == 0 || android.InList(a.Arch().ArchType.Name, arches) {
+		globalSanitizerNames = config.SanitizeDevice()
 	}
 	return android.InList(sanitizerName, globalSanitizerNames)
 }
@@ -1611,7 +1498,7 @@
 func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) {
 	// TODO(jiyong): move this info (the sanitizer name, the lib name, etc.) to cc/sanitize.go
 	// Keep only the mechanism here.
-	if ctx.Device() && sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
+	if sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
 		imageVariation := a.getImageVariation(ctx)
 		for _, target := range ctx.MultiTargets() {
 			if target.Arch.ArchType.Multilib == "lib64" {
@@ -1685,6 +1572,7 @@
 	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
 		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
 	}
+	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
 	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
 	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
 	af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, rustm)
@@ -1704,27 +1592,12 @@
 	if rustm.Target().NativeBridge == android.NativeBridgeEnabled {
 		dirInApex = filepath.Join(dirInApex, rustm.Target().NativeBridgeRelativePath)
 	}
+	dirInApex = filepath.Join(dirInApex, rustm.RelativeInstallPath())
 	fileToCopy := android.OutputFileForModule(ctx, rustm, "")
 	androidMkModuleName := rustm.BaseModuleName() + rustm.Properties.SubName
 	return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, rustm)
 }
 
-func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.PythonBinaryModule) apexFile {
-	dirInApex := "bin"
-	fileToCopy := py.HostToolPath().Path()
-	return newApexFile(ctx, fileToCopy, py.BaseModuleName(), dirInApex, pyBinary, py)
-}
-
-func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb bootstrap.GoBinaryTool) apexFile {
-	dirInApex := "bin"
-	fileToCopy := android.PathForGoBinary(ctx, gb)
-	// NB: Since go binaries are static we don't need the module for anything here, which is
-	// good since the go tool is a blueprint.Module not an android.Module like we would
-	// normally use.
-	//
-	return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil)
-}
-
 func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
 	dirInApex := filepath.Join("bin", sh.SubDir())
 	if sh.Target().NativeBridge == android.NativeBridgeEnabled {
@@ -1943,7 +1816,7 @@
 var _ android.MixedBuildBuildable = (*apexBundle)(nil)
 
 func (a *apexBundle) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
-	return a.properties.ApexType == imageApex
+	return true
 }
 
 func (a *apexBundle) QueueBazelCall(ctx android.BaseModuleContext) {
@@ -1964,13 +1837,9 @@
 		return
 	}
 
-	a.setApexTypeAndSuffix(ctx)
 	a.setPayloadFsType(ctx)
 	a.setSystemLibLink(ctx)
-
-	if a.properties.ApexType != zipApex {
-		a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
-	}
+	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 
 	bazelCtx := ctx.Config().BazelContext
 	outputs, err := bazelCtx.GetApexInfo(a.GetBazelLabel(ctx, a), android.GetConfigKey(ctx))
@@ -2005,24 +1874,18 @@
 	// part of a bundled build.
 	a.makeModulesToInstall = append(a.makeModulesToInstall, outputs.MakeModulesToInstall...)
 
-	apexType := a.properties.ApexType
-	switch apexType {
-	case imageApex:
-		a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile)
-		a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex))
-		a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs))
-		// TODO(b/239084755): Generate the java api using.xml file from Bazel.
-		a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex))
-		a.installedFilesFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.InstalledFiles))
-		installSuffix := imageApexSuffix
-		if a.isCompressed {
-			installSuffix = imageCapexSuffix
-		}
-		a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
-			a.compatSymlinks.Paths()...)
-	default:
-		panic(fmt.Errorf("internal error: unexpected apex_type for the ProcessBazelQueryResponse: %v", a.properties.ApexType))
+	a.bundleModuleFile = android.PathForBazelOut(ctx, outputs.BundleFile)
+	a.nativeApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.SymbolsUsedByApex))
+	a.nativeApisBackedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.BackingLibs))
+	// TODO(b/239084755): Generate the java api using.xml file from Bazel.
+	a.javaApisUsedByModuleFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.JavaSymbolsUsedByApex))
+	a.installedFilesFile = android.ModuleOutPath(android.PathForBazelOut(ctx, outputs.InstalledFiles))
+	installSuffix := imageApexSuffix
+	if a.isCompressed {
+		installSuffix = imageCapexSuffix
 	}
+	a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
+		a.compatSymlinks.Paths()...)
 
 	// filesInfo in mixed mode must retrieve all information about the apex's
 	// contents completely from the Starlark providers. It should never rely on
@@ -2063,9 +1926,7 @@
 }
 
 func (a *apexBundle) setCompression(ctx android.ModuleContext) {
-	if a.properties.ApexType != imageApex {
-		a.isCompressed = false
-	} else if a.testOnlyShouldForceCompression() {
+	if a.testOnlyShouldForceCompression() {
 		a.isCompressed = true
 	} else {
 		a.isCompressed = ctx.Config().ApexCompressionEnabled() && a.isCompressable()
@@ -2091,12 +1952,7 @@
 
 	// We don't need the optimization for updatable APEXes, as it might give false signal
 	// to the system health when the APEXes are still bundled (b/149805758).
-	if !forced && updatable && a.properties.ApexType == imageApex {
-		a.linkToSystemLib = false
-	}
-
-	// We also don't want the optimization for host APEXes, because it doesn't make sense.
-	if ctx.Host() {
+	if !forced && updatable {
 		a.linkToSystemLib = false
 	}
 }
@@ -2114,22 +1970,6 @@
 	}
 }
 
-func (a *apexBundle) setApexTypeAndSuffix(ctx android.ModuleContext) {
-	// Set suffix and primaryApexType depending on the ApexType
-	switch a.properties.ApexType {
-	case imageApex:
-		a.suffix = ""
-		a.primaryApexType = true
-	case zipApex:
-		if proptools.String(a.properties.Payload_type) == "zip" {
-			a.suffix = ""
-			a.primaryApexType = true
-		} else {
-			a.suffix = zipApexSuffix
-		}
-	}
-}
-
 func (a *apexBundle) isCompressable() bool {
 	return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex
 }
@@ -2176,6 +2016,9 @@
 			// If a module is directly included and also transitively depended on
 			// consider it as directly included.
 			e.transitiveDep = e.transitiveDep && f.transitiveDep
+			// If a module is added as both a JNI library and a regular shared library, consider it as a
+			// JNI library.
+			e.isJniLib = e.isJniLib || f.isJniLib
 			encountered[dest] = e
 		}
 	}
@@ -2232,14 +2075,6 @@
 			case *cc.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForExecutable(ctx, ch))
 				return true // track transitive dependencies
-			case *python.PythonBinaryModule:
-				if ch.HostToolPath().Valid() {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForPyBinary(ctx, ch))
-				}
-			case bootstrap.GoBinaryTool:
-				if a.Host() {
-					vctx.filesInfo = append(vctx.filesInfo, apexFileForGoBinary(ctx, depName, ch))
-				}
 			case *rust.Module:
 				vctx.filesInfo = append(vctx.filesInfo, apexFileForRustExecutable(ctx, ch))
 				return true // track transitive dependencies
@@ -2394,19 +2229,18 @@
 	// tags used below are private (e.g. `cc.sharedDepTag`).
 	if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) {
 		if ch, ok := child.(*cc.Module); ok {
-			if ch.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && ch.IsVndk() {
+			if ch.UseVndk() && a.useVndkAsStable(ctx) && ch.IsVndk() {
 				vctx.requireNativeLibs = append(vctx.requireNativeLibs, ":vndk")
 				return false
 			}
+
+			//TODO: b/296491928 Vendor APEX should use libbinder.ndk instead of libbinder once VNDK is fully deprecated.
+			if ch.UseVndk() && ctx.Config().IsVndkDeprecated() && child.Name() == "libbinder" {
+				return false
+			}
 			af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs)
 			af.transitiveDep = true
 
-			// Always track transitive dependencies for host.
-			if a.Host() {
-				vctx.filesInfo = append(vctx.filesInfo, af)
-				return true
-			}
-
 			abInfo := ctx.Provider(ApexBundleInfoProvider).(ApexBundleInfo)
 			if !abInfo.Contents.DirectlyInApex(depName) && (ch.IsStubs() || ch.HasStubsVariants()) {
 				// If the dependency is a stubs lib, don't include it in this APEX,
@@ -2537,11 +2371,7 @@
 	if a.testApex {
 		return false
 	}
-	// TODO(b/263309864) remove this
-	if a.Host() {
-		return false
-	}
-	if a.Device() && ctx.DeviceConfig().DeviceArch() == "" {
+	if ctx.DeviceConfig().DeviceArch() == "" {
 		return false
 	}
 	return true
@@ -2619,12 +2449,9 @@
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = vctx.filesInfo
 
-	a.setApexTypeAndSuffix(ctx)
 	a.setPayloadFsType(ctx)
 	a.setSystemLibLink(ctx)
-	if a.properties.ApexType != zipApex {
-		a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, a.primaryApexType)
-	}
+	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 
 	////////////////////////////////////////////////////////////////////////////////////////////
 	// 4) generate the build rules to create the APEX. This is done in builder.go.
@@ -2725,7 +2552,7 @@
 	module.AddProperties(&module.archProperties)
 	module.AddProperties(&module.overridableProperties)
 
-	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.overridableProperties.Overrides)
 	android.InitBazelModule(module)
@@ -2916,13 +2743,13 @@
 	// Only override the minSdkVersion value on Apexes which already specify
 	// a min_sdk_version (it's optional for non-updatable apexes), and that its
 	// min_sdk_version value is lower than the one to override with.
-	minApiLevel := minSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
+	minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
 	if minApiLevel.IsNone() {
 		return ""
 	}
 
 	overrideMinSdkValue := ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride()
-	overrideApiLevel := minSdkVersionFromValue(ctx, overrideMinSdkValue)
+	overrideApiLevel := android.MinSdkVersionFromValue(ctx, overrideMinSdkValue)
 	if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(minApiLevel) > 0 {
 		minApiLevel = overrideApiLevel
 	}
@@ -2937,26 +2764,13 @@
 
 // Returns apex's min_sdk_version ApiLevel, honoring overrides
 func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
-	return minSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx))
-}
-
-// Construct ApiLevel object from min_sdk_version string value
-func minSdkVersionFromValue(ctx android.EarlyModuleContext, value string) android.ApiLevel {
-	if value == "" {
-		return android.NoneApiLevel
-	}
-	apiLevel, err := android.ApiLevelFromUser(ctx, value)
-	if err != nil {
-		ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
-		return android.NoneApiLevel
-	}
-	return apiLevel
+	return android.MinSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx))
 }
 
 // Ensures that a lib providing stub isn't statically linked
 func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
 	// Practically, we only care about regular APEXes on the device.
-	if ctx.Host() || a.testApex || a.vndkApex {
+	if a.testApex || a.vndkApex {
 		return
 	}
 
@@ -3051,7 +2865,7 @@
 // checkApexAvailability ensures that the all the dependencies are marked as available for this APEX.
 func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
 	// Let's be practical. Availability for test, host, and the VNDK apex isn't important
-	if ctx.Host() || a.testApex || a.vndkApex {
+	if a.testApex || a.vndkApex {
 		return
 	}
 
@@ -3109,11 +2923,6 @@
 
 // checkStaticExecutable ensures that executables in an APEX are not static.
 func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) {
-	// No need to run this for host APEXes
-	if ctx.Host() {
-		return
-	}
-
 	ctx.VisitDirectDepsBlueprint(func(module blueprint.Module) {
 		if ctx.OtherModuleDependencyTag(module) != executableTag {
 			return
@@ -3716,3 +3525,12 @@
 func (a *apexBundle) IsTestApex() bool {
 	return a.testApex
 }
+
+func (a *apexBundle) useVndkAsStable(ctx android.BaseModuleContext) bool {
+	// VNDK cannot be linked if it is deprecated
+	if ctx.Config().IsVndkDeprecated() {
+		return false
+	}
+
+	return proptools.Bool(a.properties.Use_vndk_as_stable)
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index df138e0..9475f5d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -390,7 +390,7 @@
 			name: "foo.rust",
 			srcs: ["foo.rs"],
 			rlibs: ["libfoo.rlib.rust"],
-			dylibs: ["libfoo.dylib.rust"],
+			rustlibs: ["libfoo.dylib.rust"],
 			apex_available: ["myapex"],
 		}
 
@@ -518,10 +518,10 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 
 	// Make sure that Android.mk is created
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, ab)
 	var builder strings.Builder
 	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
@@ -533,7 +533,7 @@
 	optFlags := apexRule.Args["opt_flags"]
 	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
 	// Ensure that the NOTICE output is being packaged as an asset.
-	ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex_image/NOTICE")
+	ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex/NOTICE")
 
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -595,13 +595,13 @@
 		t.Errorf("Could not find all expected symlinks! foo: %t, foo_link_64: %t. Command was %s", found_foo, found_foo_link_64, copyCmds)
 	}
 
-	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
+	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
 	ensureListContains(t, fullDepsInfo, "  myjar(minSdkVersion:(no version)) <- myapex")
 	ensureListContains(t, fullDepsInfo, "  mylib2(minSdkVersion:(no version)) <- mylib")
 	ensureListContains(t, fullDepsInfo, "  myotherjar(minSdkVersion:(no version)) <- myjar")
 	ensureListContains(t, fullDepsInfo, "  mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
 
-	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
+	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
 	ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
 	ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
@@ -678,7 +678,7 @@
 		}
 
 	`)
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/myetc",
 		"javalib/myjar.jar",
 		"lib64/mylib.so",
@@ -705,7 +705,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	args := module.Rule("apexRule").Args
 	if manifest := args["manifest"]; manifest != module.Output("apex_manifest.pb").Output.String() {
 		t.Error("manifest should be apex_manifest.pb, but " + manifest)
@@ -776,7 +776,7 @@
 		},
 	}
 	for _, tc := range testCases {
-		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module+"_image")
+		module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module)
 		args := module.Rule("apexRule").Args
 		optFlags := args["opt_flags"]
 		if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) {
@@ -806,7 +806,7 @@
 			}
 		`)
 
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("file_contexts")
 		if vendor {
 			android.AssertStringDoesContain(t, "should force-label as vendor_apex_metadata_file",
 				rule.RuleParams.Command,
@@ -819,57 +819,6 @@
 	}
 }
 
-func TestBasicZipApex(t *testing.T) {
-	ctx := testApex(t, `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			payload_type: "zip",
-			native_shared_libs: ["mylib"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		cc_library {
-			name: "mylib",
-			srcs: ["mylib.cpp"],
-			shared_libs: ["mylib2"],
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
-		}
-
-		cc_library {
-			name: "mylib2",
-			srcs: ["mylib.cpp"],
-			system_shared_libs: [],
-			stl: "none",
-			apex_available: [ "myapex" ],
-		}
-	`)
-
-	zipApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_zip").Rule("zipApexRule")
-	copyCmds := zipApexRule.Args["copy_commands"]
-
-	// Ensure that main rule creates an output
-	ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned")
-
-	// Ensure that APEX variant is created for the direct dep
-	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
-
-	// Ensure that APEX variant is created for the indirect dep
-	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
-
-	// Ensure that both direct and indirect deps are copied into apex
-	ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so")
-	ensureContains(t, copyCmds, "image.zipapex/lib64/mylib2.so")
-}
-
 func TestApexWithStubs(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -946,7 +895,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -987,7 +936,7 @@
 	// Ensure that genstub for apex-provided lib is invoked with --apex
 	ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex")
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"lib64/mylib.so",
 		"lib64/mylib3.so",
 		"lib64/mylib4.so",
@@ -1003,7 +952,7 @@
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
 }
 
@@ -1063,7 +1012,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that indirect stubs dep is not included
@@ -1141,7 +1090,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1172,7 +1121,7 @@
 	// Ensure that genstub is invoked with --systemapi
 	ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi")
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"lib64/mylib.so",
 		"lib64/mylib3.so",
 		"lib64/mylib4.so",
@@ -1308,7 +1257,7 @@
 
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1332,10 +1281,10 @@
 	// Ensure that libfoo stubs is not linking to libbar (since it is a stubs)
 	ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
 
-	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
+	fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
 	ensureListContains(t, fullDepsInfo, "  libfoo(minSdkVersion:(no version)) (external) <- mylib")
 
-	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
+	flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
 	ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
 }
 
@@ -1426,7 +1375,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -1442,7 +1391,7 @@
 
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so")
 
-	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 	ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so")
 }
@@ -1503,7 +1452,7 @@
 		}	`)
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{
 		"lib64/bionic/libc.so",
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
@@ -1556,7 +1505,7 @@
 		`)
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+	ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime", []string{
 		"lib64/bionic/libc.so",
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
@@ -1637,12 +1586,12 @@
 			)
 
 			// Ensure that LLNDK dep is not included
-			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 				"lib64/mylib.so",
 			})
 
 			// Ensure that LLNDK dep is required
-			apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+			apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 			ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
 			ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
 
@@ -1702,7 +1651,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that mylib, libm, libdl are included.
@@ -2076,11 +2025,11 @@
 	depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton")
 	inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings()
 	android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs,
-		"out/soong/.intermediates/myapex/android_common_myapex_image/depsinfo/flatlist.txt")
+		"out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt")
 	android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs,
-		"out/soong/.intermediates/myapex2/android_common_myapex2_image/depsinfo/flatlist.txt")
+		"out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt")
 
-	myapex := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	myapex := ctx.ModuleForTests("myapex", "android_common_myapex")
 	flatlist := strings.Split(myapex.Output("depsinfo/flatlist.txt").BuildParams.Args["content"], "\\n")
 	android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep",
 		flatlist, "libbar(minSdkVersion:(no version)) (external)")
@@ -2794,7 +2743,7 @@
 			name: "myapex",
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
-			binaries: ["mybin"],
+			binaries: ["mybin", "mybin.rust"],
 			prebuilts: ["myetc"],
 			compile_multilib: "both",
 			updatable: false,
@@ -2829,9 +2778,16 @@
 			stl: "none",
 			apex_available: [ "myapex" ],
 		}
+
+		rust_binary {
+			name: "mybin.rust",
+			srcs: ["foo.rs"],
+			relative_install_path: "rust_subdir",
+			apex_available: [ "myapex" ],
+		}
 	`)
 
-	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("generateFsConfig")
+	generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
 	// Ensure that the subdirectories are all listed
@@ -2847,6 +2803,7 @@
 	ensureContains(t, cmd, "/bin ")
 	ensureContains(t, cmd, "/bin/foo ")
 	ensureContains(t, cmd, "/bin/foo/bar ")
+	ensureContains(t, cmd, "/bin/rust_subdir ")
 }
 
 func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
@@ -2895,7 +2852,7 @@
 			},
 		}
 	`, withNativeBridgeEnabled)
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"bin/foo/bar/mybin",
 		"bin/foo/bar/mybin64",
 		"bin/arm/foo/bar/mybin",
@@ -2935,14 +2892,14 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		"bin/mybin",
 		"lib64/libfoo.so",
 		// TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
 		"lib64/libc++.so",
 	})
 
-	apexBundle := result.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := result.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, result.TestContext, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -2952,7 +2909,7 @@
 	installPath := "out/target/product/test_device/vendor/apex"
 	ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath)
 
-	apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListNotContains(t, requireNativeLibs, ":vndk")
 }
@@ -3029,7 +2986,11 @@
 			vendor: true,
 			shared_libs: ["libvndk", "libvendor"],
 		}
-	`)
+	`,
+		android.FixtureModifyConfig(func(config android.Config) {
+			config.TestProductVariables.KeepVndk = proptools.BoolPtr(true)
+		}),
+	)
 
 	vendorVariant := "android_vendor.29_arm64_armv8-a"
 
@@ -3091,10 +3052,10 @@
 				ensureListContains(t, libs, lib)
 			}
 			// Check apex contents
-			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName+"_image", tc.contents)
+			ensureExactContents(t, ctx, tc.apexName, "android_common_"+tc.apexName, tc.contents)
 
 			// Check "requireNativeLibs"
-			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName+"_image").Rule("apexManifestRule")
+			apexManifestRule := ctx.ModuleForTests(tc.apexName, "android_common_"+tc.apexName).Rule("apexManifestRule")
 			requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
 			if tc.requireVndkNamespace {
 				ensureListContains(t, requireNativeLibs, ":vndk")
@@ -3170,7 +3131,7 @@
 					`+tc.additionalProp+`
 				}
 			`)
-			ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+			ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 				"etc/firmware/myfirmware.bin",
 			})
 		})
@@ -3199,7 +3160,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -3228,7 +3189,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -3331,7 +3292,7 @@
 	}
 
 	// check the APK certs. It should be overridden to myapex.certificate.override
-	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk").Args["certificates"]
+	certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"]
 	if certs != "testkey.override.x509.pem testkey.override.pk8" {
 		t.Errorf("cert and private key %q are not %q", certs,
 			"testkey.override.509.pem testkey.override.pk8")
@@ -3351,7 +3312,7 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3374,7 +3335,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3397,7 +3358,7 @@
 				name: "myapex.certificate",
 				certificate: "testkey",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "testkey.x509.pem testkey.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3421,7 +3382,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3440,7 +3401,7 @@
 				public_key: "testkey.avbpubkey",
 				private_key: "testkey.pem",
 			}`)
-		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk")
 		expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3464,7 +3425,7 @@
 				name: "myapex.certificate.override",
 				certificate: "testkey.override",
 			}`)
-		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest_image").Rule("signapk")
+		rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk")
 		expected := "testkey.override.x509.pem testkey.override.pk8"
 		if actual := rule.Args["certificates"]; actual != expected {
 			t.Errorf("certificates should be %q, not %q", expected, actual)
@@ -3645,10 +3606,6 @@
 	module := ctx.ModuleForTests(moduleName, variant)
 	apexRule := module.MaybeRule("apexRule")
 	apexDir := "/image.apex/"
-	if apexRule.Rule == nil {
-		apexRule = module.Rule("zipApexRule")
-		apexDir = "/image.zipapex/"
-	}
 	copyCmds := apexRule.Args["copy_commands"]
 	var ret []fileInApex
 	for _, cmd := range strings.Split(copyCmds, "&&") {
@@ -3858,8 +3815,9 @@
 			}
 		`+vndkLibrariesTxtFiles("current"), android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = proptools.StringPtr(tc.vndkVersion)
+				variables.KeepVndk = proptools.BoolPtr(true)
 			}))
-			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", tc.expectedFiles)
+			ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", tc.expectedFiles)
 		})
 	}
 }
@@ -3914,7 +3872,7 @@
 			"libvndk.so":     nil,
 			"libvndk.arm.so": nil,
 		}))
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndk.so",
 		"lib/libvndk.arm.so",
 		"lib64/libvndk.so",
@@ -4010,7 +3968,7 @@
 			"libvndk27_x86_64.so": nil,
 		}))
 
-	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{
 		"lib/libvndk27_arm.so",
 		"lib64/libvndk27_arm64.so",
 		"etc/*",
@@ -4039,7 +3997,7 @@
 		}`+vndkLibrariesTxtFiles("28", "current"))
 
 	assertApexName := func(expected, moduleName string) {
-		module := ctx.ModuleForTests(moduleName, "android_common_image")
+		module := ctx.ModuleForTests(moduleName, "android_common")
 		apexManifestRule := module.Rule("apexManifestRule")
 		ensureContains(t, apexManifestRule.Args["opt"], "-v name "+expected)
 	}
@@ -4080,7 +4038,7 @@
 		`+vndkLibrariesTxtFiles("current"),
 		withNativeBridgeEnabled)
 
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndk.so",
 		"lib64/libvndk.so",
 		"lib/libc++.so",
@@ -4183,7 +4141,7 @@
 		}),
 	)
 
-	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.v27", "android_common", []string{
 		"lib/libvndk27binder32.so",
 		"etc/*",
 	})
@@ -4220,10 +4178,10 @@
 		"libz.map.txt": nil,
 	}))
 
-	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common_image").Rule("apexManifestRule")
+	apexManifestRule := ctx.ModuleForTests("com.android.vndk.current", "android_common").Rule("apexManifestRule")
 	provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"out/soong/.intermediates/libz/android_vendor.29_arm64_armv8-a_shared/libz.so:lib64/libz.so",
 		"out/soong/.intermediates/libz/android_vendor.29_arm_armv7-a-neon_shared/libz.so:lib/libz.so",
 		"*/*",
@@ -4379,7 +4337,7 @@
 		}))
 
 	// Should embed the prebuilt VNDK libraries in the apex
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"bin/foo",
 		"prebuilts/vndk/libc++.so:lib64/libc++.so",
 		"prebuilts/vndk/libvndk.so:lib64/libvndk.so",
@@ -4393,7 +4351,7 @@
 	android.AssertStringDoesContain(t, "should link to prebuilt libunwind", ldRule.Args["libFlags"], "prebuilts/vndk/libunwind.a")
 
 	// Should declare the LLNDK library as a "required" external dependency
-	manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	manifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	requireNativeLibs := names(manifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, requireNativeLibs, "libllndk.so")
 }
@@ -4506,25 +4464,25 @@
 	var apexManifestRule android.TestingBuildParams
 	var provideNativeLibs, requireNativeLibs []string
 
-	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListEmpty(t, provideNativeLibs)
 	ensureListContains(t, requireNativeLibs, "libfoo.so")
 
-	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libfoo.so")
 	ensureListEmpty(t, requireNativeLibs)
 
-	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained_image").Rule("apexManifestRule")
+	apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule")
 	provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"])
 	requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"])
 	ensureListContains(t, provideNativeLibs, "libbar.so")
@@ -4560,7 +4518,7 @@
 		"OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234",
 	}))
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexManifestRule := module.Rule("apexManifestRule")
 	ensureContains(t, apexManifestRule.Args["default_version"], "1234")
 }
@@ -4623,7 +4581,7 @@
 			}
 		`, testCase.compileMultiLibProp),
 		)
-		module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+		module := ctx.ModuleForTests("myapex", "android_common_myapex")
 		apexRule := module.Rule("apexRule")
 		copyCmds := apexRule.Args["copy_commands"]
 		for _, containedLib := range testCase.containedLibs {
@@ -4662,7 +4620,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -4716,7 +4674,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -4806,7 +4764,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that main rule creates an output
@@ -4890,7 +4848,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that apex variant is created for the direct dep
@@ -4926,7 +4884,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh")
@@ -4960,7 +4918,7 @@
 				}
 			`)
 
-			apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+			apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 			expected := "out/soong/target/product/test_device/" + tc.partition + "/apex"
 			actual := apex.installDir.RelativeToTop().String()
 			if actual != expected {
@@ -4984,7 +4942,7 @@
 			private_key: "testkey.pem",
 		}
 	`)
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts")
 }
@@ -5042,7 +5000,7 @@
 	`, withFiles(map[string][]byte{
 		"product_specific_file_contexts": nil,
 	}))
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
 }
@@ -5070,7 +5028,7 @@
 	`, withFiles(map[string][]byte{
 		"product_specific_file_contexts": nil,
 	}))
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	rule := module.Output("file_contexts")
 	ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
 }
@@ -6128,7 +6086,7 @@
 		}
 	`)
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that test dep (and their transitive dependencies) are copied into apex.
@@ -6145,7 +6103,7 @@
 	ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
 
 	// Ensure the module is correctly translated.
-	bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, bundle)
 	name := bundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -6228,7 +6186,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 	ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar")
@@ -6292,7 +6250,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6398,7 +6356,7 @@
 		}
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6443,7 +6401,7 @@
 		"AppFooPrebuilt.apk": nil,
 	}))
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"app/AppFoo@TEST.BUILD_ID/AppFooPrebuilt.apk",
 	})
 }
@@ -6473,7 +6431,7 @@
 
 	`)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -6790,22 +6748,32 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}
+		override_apex {
+			name: "myoverrideapex",
+			base: "bar",
+		}
 	`)
 
-	fooManifestRule := result.ModuleForTests("foo", "android_common_foo_image").Rule("apexManifestRule")
+	fooManifestRule := result.ModuleForTests("foo", "android_common_foo").Rule("apexManifestRule")
 	fooExpectedDefaultVersion := android.DefaultUpdatableModuleVersion
 	fooActualDefaultVersion := fooManifestRule.Args["default_version"]
 	if fooActualDefaultVersion != fooExpectedDefaultVersion {
 		t.Errorf("expected to find defaultVersion %q; got %q", fooExpectedDefaultVersion, fooActualDefaultVersion)
 	}
 
-	barManifestRule := result.ModuleForTests("bar", "android_common_bar_image").Rule("apexManifestRule")
+	barManifestRule := result.ModuleForTests("bar", "android_common_bar").Rule("apexManifestRule")
 	defaultVersionInt, _ := strconv.Atoi(android.DefaultUpdatableModuleVersion)
 	barExpectedDefaultVersion := fmt.Sprint(defaultVersionInt + 3)
 	barActualDefaultVersion := barManifestRule.Args["default_version"]
 	if barActualDefaultVersion != barExpectedDefaultVersion {
 		t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
 	}
+
+	overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar").Rule("apexManifestRule")
+	overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
+	if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
+		t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
+	}
 }
 
 func TestApexAvailable_ApexAvailableName(t *testing.T) {
@@ -7161,8 +7129,8 @@
 		}
 	`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
 
-	originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
-	overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule)
+	originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule)
+	overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Module().(android.OverridableModule)
 	if originalVariant.GetOverriddenBy() != "" {
 		t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
 	}
@@ -7170,7 +7138,7 @@
 		t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
 	}
 
-	module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex")
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
@@ -7260,7 +7228,7 @@
 
 	`, withApexGlobalMinSdkVersionOverride(&minSdkOverride31))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -7319,7 +7287,7 @@
 
 	`, withApexGlobalMinSdkVersionOverride(&minSdkOverride29))
 
-	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
 	// Ensure that direct non-stubs dep is always included
@@ -7357,7 +7325,7 @@
 		}
 	`, withUnbundledBuild)
 
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	args := module.Rule("apexRule").Args
 	ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String())
 	ensureNotContains(t, args["opt_flags"], "--no_hashtree")
@@ -7421,7 +7389,7 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
 	})
@@ -7470,7 +7438,7 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/bar.jar",
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
@@ -7522,7 +7490,7 @@
 	`, withFiles(filesForSdkLibrary))
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
 	})
@@ -7611,7 +7579,7 @@
 	)
 
 	// java_sdk_library installs both impl jar and permission XML
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"javalib/bar.jar",
 		"javalib/foo.jar",
 		"etc/permissions/foo.xml",
@@ -7691,7 +7659,7 @@
 		}
 	`)
 	ctx := result.TestContext
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/compatconfig/myjar-platform-compat-config.xml",
 		"javalib/myjar.jar",
 	})
@@ -7786,7 +7754,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	name := apexBundle.BaseModuleName()
 	prefix := "TARGET_"
@@ -7925,13 +7893,13 @@
 	// For unbundled build, symlink shouldn't exist regardless of whether an APEX
 	// is updatable or not
 	ctx := testApex(t, bp, withUnbundledBuild)
-	files := getFiles(t, ctx, "myapex", "android_common_myapex_image")
+	files := getFiles(t, ctx, "myapex", "android_common_myapex")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib_ext.so")
 
-	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")
@@ -7939,13 +7907,13 @@
 
 	// For bundled build, symlink to the system for the non-updatable APEXes only
 	ctx = testApex(t, bp)
-	files = getFiles(t, ctx, "myapex", "android_common_myapex_image")
+	files = getFiles(t, ctx, "myapex", "android_common_myapex")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureSymlinkExists(t, files, "lib64/myotherlib.so", "/system/lib64/myotherlib.so")             // this is symlink
 	ensureSymlinkExists(t, files, "lib64/myotherlib_ext.so", "/system_ext/lib64/myotherlib_ext.so") // this is symlink
 
-	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable_image")
+	files = getFiles(t, ctx, "myapex.updatable", "android_common_myapex.updatable")
 	ensureRealfileExists(t, files, "javalib/myjar.jar")
 	ensureRealfileExists(t, files, "lib64/mylib.so")
 	ensureRealfileExists(t, files, "lib64/myotherlib.so")     // this is a real file
@@ -7991,7 +7959,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -8009,7 +7977,8 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			jni_libs: ["mylib", "libfoo.rust"],
+			binaries: ["mybin"],
+			jni_libs: ["mylib", "mylib3", "libfoo.rust"],
 			updatable: false,
 		}
 
@@ -8036,6 +8005,24 @@
 			apex_available: [ "myapex" ],
 		}
 
+		// Used as both a JNI library and a regular shared library.
+		cc_library {
+			name: "mylib3",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
+		cc_binary {
+			name: "mybin",
+			srcs: ["mybin.cpp"],
+			shared_libs: ["mylib3"],
+			system_shared_libs: [],
+			stl: "none",
+			apex_available: [ "myapex" ],
+		}
+
 		rust_ffi_shared {
 			name: "libfoo.rust",
 			crate_name: "foo",
@@ -8057,12 +8044,14 @@
 
 	`)
 
-	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
 	// Notice mylib2.so (transitive dep) is not added as a jni_lib
-	ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so")
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so mylib3.so")
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
+		"bin/mybin",
 		"lib64/mylib.so",
 		"lib64/mylib2.so",
+		"lib64/mylib3.so",
 		"lib64/libfoo.rust.so",
 		"lib64/libc++.so", // auto-added to libfoo.rust by Soong
 		"lib64/liblog.so", // auto-added to libfoo.rust by Soong
@@ -8120,7 +8109,7 @@
 		}
 		`, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"}))
 
-	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("bundle_config.json")
+	bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("bundle_config.json")
 	content := bundleConfigRule.Args["content"]
 
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
@@ -8146,7 +8135,7 @@
 			name: "AppSet",
 			set: "AppSet.apks",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	bundleConfigRule := mod.Output("bundle_config.json")
 	content := bundleConfigRule.Args["content"]
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
@@ -9184,12 +9173,12 @@
 			`),
 	}))
 
-	rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
+	rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("diffApexContentRule")
 	if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
 		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
 	}
 
-	rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
+	rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Rule("diffApexContentRule")
 	if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
 		t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
 	}
@@ -9250,14 +9239,14 @@
 		}),
 	)
 
-	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("compressRule")
+	compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("compressRule")
 	ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned")
 
-	signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Description("sign compressedApex")
+	signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex").Description("sign compressedApex")
 	ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String())
 
 	// Make sure output of bundle is .capex
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	ensureContains(t, ab.outputFile.String(), "myapex.capex")
 
 	// Verify android.mk rules
@@ -9309,7 +9298,7 @@
 		}
 	`)
 
-	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, ab)
 	var builder strings.Builder
 	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
@@ -9366,7 +9355,7 @@
 	ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so")
 
 	// It shouldn't appear in the copy cmd as well.
-	copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule").Args["copy_commands"]
+	copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule").Args["copy_commands"]
 	ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so")
 }
 
@@ -9531,28 +9520,6 @@
 	}
 }
 
-func TestHostApexInHostOnlyBuild(t *testing.T) {
-	testApex(t, `
-		apex {
-			name: "myapex",
-			host_supported: true,
-			key: "myapex.key",
-			updatable: false,
-			payload_type: "zip",
-		}
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-	`,
-		android.FixtureModifyConfig(func(config android.Config) {
-			// We may not have device targets in all builds, e.g. in
-			// prebuilts/build-tools/build-prebuilts.sh
-			config.Targets[android.Android] = []android.Target{}
-		}))
-}
-
 func TestApexJavaCoverage(t *testing.T) {
 	bp := `
 		apex {
@@ -9706,7 +9673,7 @@
 		dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
 	)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -9782,7 +9749,7 @@
 		}
 	`)
 
-	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	data := android.AndroidMkDataForTest(t, ctx, apexBundle)
 	var builder strings.Builder
 	data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
@@ -9805,7 +9772,7 @@
 		}
 	`)
 
-	bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
 	bundle.makeModulesToInstall = append(bundle.makeModulesToInstall, "foo")
 	data := android.AndroidMkDataForTest(t, ctx, bundle)
 	var builder strings.Builder
@@ -9823,12 +9790,12 @@
 		{
 			name:          "test_using_output",
 			ref:           ":myapex",
-			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.capex:myapex.capex"},
+			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.capex:myapex.capex"},
 		},
 		{
 			name:          "test_using_apex",
 			ref:           ":myapex{.apex}",
-			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex_image/myapex.apex:myapex.apex"},
+			expected_data: []string{"out/soong/.intermediates/myapex/android_common_myapex/myapex.apex:myapex.apex"},
 		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
@@ -10564,14 +10531,14 @@
 		}
 		`
 	ctx := testApex(t, bp)
-	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	module := ctx.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := module.MaybeRule("apexRule")
 	if apexRule.Rule == nil {
 		t.Errorf("Expecting regular apex rule but a non regular apex rule found")
 	}
 
 	ctx = testApex(t, bp, android.FixtureModifyConfig(android.SetTrimmedApexEnabledForTests))
-	trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("TrimmedApexRule")
+	trimmedApexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("TrimmedApexRule")
 	libs_to_trim := trimmedApexRule.Args["libs_to_trim"]
 	android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libfoo")
 	android.AssertStringDoesContain(t, "missing lib to trim", libs_to_trim, "libbar")
@@ -10591,7 +10558,7 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	generateFsRule := mod.Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
@@ -10612,7 +10579,7 @@
 			public_key: "testkey.avbpubkey",
 			private_key: "testkey.pem",
 		}`)
-	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex")
 	generateFsRule := mod.Rule("generateFsConfig")
 	cmd := generateFsRule.RuleParams.Command
 
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index f30f7f6..89ea004 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -302,14 +302,14 @@
 			java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"),
 		).RunTest(t)
 
-		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			"etc/boot-image.prof",
 			"etc/classpaths/bootclasspath.pb",
 			"javalib/bar.jar",
 			"javalib/foo.jar",
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
 		})
@@ -332,7 +332,7 @@
 			dexpreopt.FixtureDisableDexpreoptBootImages(true),
 		).RunTest(t)
 
-		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			"etc/boot-image.prof",
 			"etc/classpaths/bootclasspath.pb",
 			"javalib/bar.jar",
@@ -351,7 +351,7 @@
 			dexpreopt.FixtureDisableGenerateProfile(true),
 		).RunTest(t)
 
-		files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art_image")
+		files := getFiles(t, result.TestContext, "com.android.art", "android_common_com.android.art")
 		for _, file := range files {
 			matched, _ := path.Match("etc/boot-image.prof", file.path)
 			android.AssertBoolEquals(t, "\"etc/boot-image.prof\" should not be in the APEX", matched, false)
@@ -380,7 +380,7 @@
 			"javalib/foo.jar",
 		})
 
-		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
 			`art-bootclasspath-fragment`,
 			`com.android.art.key`,
 			`prebuilt_com.android.art`,
@@ -635,7 +635,7 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		// This does not include art, oat or vdex files as they are only included for the art boot
 		// image.
 		"etc/classpaths/bootclasspath.pb",
@@ -643,12 +643,12 @@
 		"javalib/foo.jar",
 	})
 
-	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		`myapex.key`,
 		`mybootclasspathfragment`,
 	})
 
-	apex := result.ModuleForTests("myapex", "android_common_myapex_image")
+	apex := result.ModuleForTests("myapex", "android_common_myapex")
 	apexRule := apex.Rule("apexRule")
 	copyCommands := apexRule.Args["copy_commands"]
 
@@ -665,7 +665,7 @@
 		}
 		android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
 
-		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
+		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex/image.apex/javalib/%s.jar", expectedDexJar, name)
 		android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
 	}
 
diff --git a/apex/bp2build_test.go b/apex/bp2build_test.go
index b1b6a75..6bab67d 100644
--- a/apex/bp2build_test.go
+++ b/apex/bp2build_test.go
@@ -80,7 +80,7 @@
 		}),
 	).RunTestWithBp(t, bp)
 
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	m := result.ModuleForTests("foo", "android_common_foo").Module()
 	ab, ok := m.(*apexBundle)
 
 	if !ok {
@@ -206,7 +206,7 @@
 		}),
 	).RunTestWithBp(t, bp)
 
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	m := result.ModuleForTests("foo", "android_common_foo").Module()
 	ab, ok := m.(*apexBundle)
 
 	if !ok {
@@ -299,7 +299,7 @@
 		}),
 	).RunTestWithBp(t, bp)
 
-	m := result.ModuleForTests("foo", "android_common_foo_image").Module()
+	m := result.ModuleForTests("foo", "android_common_foo").Module()
 	ab, ok := m.(*apexBundle)
 	if !ok {
 		t.Fatalf("Expected module to be an apexBundle, was not")
@@ -483,7 +483,7 @@
 				}),
 			).RunTest(t)
 
-			m := result.ModuleForTests("foo", "android_common_override_foo_foo_image").Module()
+			m := result.ModuleForTests("foo", "android_common_override_foo_foo").Module()
 			ab, ok := m.(*apexBundle)
 			if !ok {
 				t.Fatalf("Expected module to be an apexBundle, was not")
diff --git a/apex/builder.go b/apex/builder.go
index db66a72..1204dbb 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -75,6 +75,8 @@
 	pctx.HostBinToolVariable("deapexer", "deapexer")
 	pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
 	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")
 }
 
 var (
@@ -179,19 +181,6 @@
 	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
 		"opt_flags", "manifest", "libs_to_trim")
 
-	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
-		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(. ${out}.copy_commands) && ` +
-			`APEXER_TOOL_PATH=${tool_path} ` +
-			`${apexer} --force --manifest ${manifest} ` +
-			`--payload_type zip ` +
-			`${image_dir} ${out} `,
-		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
-		Rspfile:        "${out}.copy_commands",
-		RspfileContent: "${copy_commands}",
-		Description:    "ZipAPEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest")
-
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
 		blueprint.RuleParams{
 			Command:     `${aapt2} convert --output-format proto $in -o $out`,
@@ -235,6 +224,18 @@
 		CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
 		Description: "run apex_sepolicy_tests",
 	})
+
+	apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{
+		Command:     `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`,
+		CommandDeps: []string{"${conv_linker_config}"},
+		Description: "run apex_linkerconfig_validation",
+	}, "image_dir")
+
+	apexVintfFragmentsValidationRule = pctx.StaticRule("apexVintfFragmentsValidationRule", blueprint.RuleParams{
+		Command:     `/bin/bash -c '(shopt -s nullglob; for f in ${image_dir}/etc/vintf/*.xml; do VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i "$$f" > /dev/null; done)' && touch ${out}`,
+		CommandDeps: []string{"${assemble_vintf}"},
+		Description: "run apex_vintf_validation",
+	}, "image_dir")
 )
 
 // buildManifest creates buile rules to modify the input apex_manifest.json to add information
@@ -369,21 +370,16 @@
 		// 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"
 	}
-	switch a.properties.ApexType {
-	case imageApex:
-		// remove old file
-		rule.Command().Text("rm").FlagWithOutput("-f ", output)
-		// copy file_contexts
-		rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
-		// new line
-		rule.Command().Text("echo").Text(">>").Output(output)
-		if !useFileContextsAsIs {
-			// force-label /apex_manifest.pb and /
-			rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
-			rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output)
-		}
-	default:
-		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
+	// remove old file
+	rule.Command().Text("rm").FlagWithOutput("-f ", output)
+	// copy file_contexts
+	rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+	// new line
+	rule.Command().Text("echo").Text(">>").Output(output)
+	if !useFileContextsAsIs {
+		// force-label /apex_manifest.pb and /
+		rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(forceLabel).Text(">>").Output(output)
+		rule.Command().Text("echo").Text("/").Text(forceLabel).Text(">>").Output(output)
 	}
 
 	rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
@@ -464,8 +460,7 @@
 
 // buildApex creates build rules to build an APEX using apexer.
 func (a *apexBundle) buildApex(ctx android.ModuleContext) {
-	apexType := a.properties.ApexType
-	suffix := apexType.suffix()
+	suffix := imageApexSuffix
 	apexName := a.BaseModuleName()
 
 	////////////////////////////////////////////////////////////////////////////////////////////
@@ -604,263 +599,247 @@
 	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
 
-	if apexType == imageApex {
+	////////////////////////////////////////////////////////////////////////////////////
+	// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
+	// in this APEX. The file will be used by apexer in later steps.
+	cannedFsConfig := a.buildCannedFsConfig(ctx)
+	implicitInputs = append(implicitInputs, cannedFsConfig)
 
-		////////////////////////////////////////////////////////////////////////////////////
-		// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
-		// in this APEX. The file will be used by apexer in later steps.
-		cannedFsConfig := a.buildCannedFsConfig(ctx)
-		implicitInputs = append(implicitInputs, cannedFsConfig)
+	////////////////////////////////////////////////////////////////////////////////////
+	// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
+	// TODO(jiyong): use the RuleBuilder
+	optFlags := []string{}
 
-		////////////////////////////////////////////////////////////////////////////////////
-		// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
-		// TODO(jiyong): use the RuleBuilder
-		optFlags := []string{}
+	fileContexts := a.buildFileContexts(ctx)
+	implicitInputs = append(implicitInputs, fileContexts)
 
-		fileContexts := a.buildFileContexts(ctx)
-		implicitInputs = append(implicitInputs, fileContexts)
+	implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
+	optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
 
-		implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
-		optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
+	manifestPackageName := a.getOverrideManifestPackageName(ctx)
+	if manifestPackageName != "" {
+		optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+	}
 
-		manifestPackageName := a.getOverrideManifestPackageName(ctx)
-		if manifestPackageName != "" {
-			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+	if a.properties.AndroidManifest != nil {
+		androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+
+		if a.testApex {
+			androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
 		}
 
-		if a.properties.AndroidManifest != nil {
-			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+		implicitInputs = append(implicitInputs, androidManifestFile)
+		optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+	} else if a.testApex {
+		optFlags = append(optFlags, "--test_only")
+	}
 
-			if a.testApex {
-				androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
-			}
+	// Determine target/min sdk version from the context
+	// TODO(jiyong): make this as a function
+	moduleMinSdkVersion := a.minSdkVersion(ctx)
+	minSdkVersion := moduleMinSdkVersion.String()
 
-			implicitInputs = append(implicitInputs, androidManifestFile)
-			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
-		} else if a.testApex {
-			optFlags = append(optFlags, "--test_only")
-		}
-
-		// Determine target/min sdk version from the context
-		// TODO(jiyong): make this as a function
-		moduleMinSdkVersion := a.minSdkVersion(ctx)
-		minSdkVersion := moduleMinSdkVersion.String()
-
-		// bundletool doesn't understand what "current" is. We need to transform it to
-		// codename
-		if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
-			minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
-
-			if java.UseApiFingerprint(ctx) {
-				minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
-				implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
-			}
-		}
-		// apex module doesn't have a concept of target_sdk_version, hence for the time
-		// being targetSdkVersion == default targetSdkVersion of the branch.
-		targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
+	// bundletool doesn't understand what "current" is. We need to transform it to
+	// codename
+	if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
+		minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
 
 		if java.UseApiFingerprint(ctx) {
-			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+			minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
 			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
 		}
-		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
-		optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
+	}
+	// apex module doesn't have a concept of target_sdk_version, hence for the time
+	// being targetSdkVersion == default targetSdkVersion of the branch.
+	targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
 
-		if a.overridableProperties.Logging_parent != "" {
-			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
-		}
+	if java.UseApiFingerprint(ctx) {
+		targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
+		implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
+	}
+	optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
+	optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
 
-		// Create a NOTICE file, and embed it as an asset file in the APEX.
-		htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
-		android.BuildNoticeHtmlOutputFromLicenseMetadata(
-			ctx, htmlGzNotice, "", "",
-			[]string{
-				android.PathForModuleInstall(ctx).String() + "/",
-				android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
-			})
-		noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
-		builder := android.NewRuleBuilder(pctx, ctx)
-		builder.Command().Text("cp").
-			Input(htmlGzNotice).
-			Output(noticeAssetPath)
-		builder.Build("notice_dir", "Building notice dir")
-		implicitInputs = append(implicitInputs, noticeAssetPath)
-		optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
+	if a.overridableProperties.Logging_parent != "" {
+		optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
+	}
 
-		// Apexes which are supposed to be installed in builtin dirs(/system, etc)
-		// don't need hashtree for activation. Therefore, by removing hashtree from
-		// apex bundle (filesystem image in it, to be specific), we can save storage.
-		needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
-			a.shouldGenerateHashtree()
-		if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
-			needHashTree = true
-		}
-		if !needHashTree {
-			optFlags = append(optFlags, "--no_hashtree")
-		}
-
-		if a.testOnlyShouldSkipPayloadSign() {
-			optFlags = append(optFlags, "--unsigned_payload")
-		}
-
-		if moduleMinSdkVersion == android.SdkVersion_Android10 {
-			implicitInputs = append(implicitInputs, a.manifestJsonOut)
-			optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
-		}
-
-		optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
-
-		if a.dynamic_common_lib_apex() {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        DCLAApexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-				},
-			})
-		} else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        TrimmedApexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-					"libs_to_trim":     strings.Join(a.libs_to_trim(ctx), ","),
-				},
-			})
-		} else {
-			ctx.Build(pctx, android.BuildParams{
-				Rule:        apexRule,
-				Implicits:   implicitInputs,
-				Output:      unsignedOutputFile,
-				Description: "apex (" + apexType.name() + ")",
-				Args: map[string]string{
-					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-					"image_dir":        imageDir.String(),
-					"copy_commands":    strings.Join(copyCommands, " && "),
-					"manifest":         a.manifestPbOut.String(),
-					"file_contexts":    fileContexts.String(),
-					"canned_fs_config": cannedFsConfig.String(),
-					"key":              a.privateKeyFile.String(),
-					"opt_flags":        strings.Join(optFlags, " "),
-				},
-			})
-		}
-
-		// TODO(jiyong): make the two rules below as separate functions
-		apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
-		bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
-		a.bundleModuleFile = bundleModuleFile
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexProtoConvertRule,
-			Input:       unsignedOutputFile,
-			Output:      apexProtoFile,
-			Description: "apex proto convert",
+	// Create a NOTICE file, and embed it as an asset file in the APEX.
+	htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
+	android.BuildNoticeHtmlOutputFromLicenseMetadata(
+		ctx, htmlGzNotice, "", "",
+		[]string{
+			android.PathForModuleInstall(ctx).String() + "/",
+			android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
 		})
+	noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().Text("cp").
+		Input(htmlGzNotice).
+		Output(noticeAssetPath)
+	builder.Build("notice_dir", "Building notice dir")
+	implicitInputs = append(implicitInputs, noticeAssetPath)
+	optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
 
-		implicitInputs = append(implicitInputs, unsignedOutputFile)
+	// Apexes which are supposed to be installed in builtin dirs(/system, etc)
+	// don't need hashtree for activation. Therefore, by removing hashtree from
+	// apex bundle (filesystem image in it, to be specific), we can save storage.
+	needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
+		a.shouldGenerateHashtree()
+	if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
+		needHashTree = true
+	}
+	if !needHashTree {
+		optFlags = append(optFlags, "--no_hashtree")
+	}
 
-		// Run coverage analysis
-		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+	if a.testOnlyShouldSkipPayloadSign() {
+		optFlags = append(optFlags, "--unsigned_payload")
+	}
+
+	if moduleMinSdkVersion == android.SdkVersion_Android10 {
+		implicitInputs = append(implicitInputs, a.manifestJsonOut)
+		optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
+	}
+
+	optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
+
+	if a.dynamic_common_lib_apex() {
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        generateAPIsUsedbyApexRule,
-			Implicits:   implicitInputs,
-			Description: "coverage",
-			Output:      apisUsedbyOutputFile,
-			Args: map[string]string{
-				"image_dir": imageDir.String(),
-				"readelf":   "${config.ClangBin}/llvm-readelf",
-			},
-		})
-		a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
-
-		var nativeLibNames []string
-		for _, f := range a.filesInfo {
-			if f.class == nativeSharedLib {
-				nativeLibNames = append(nativeLibNames, f.stem())
-			}
-		}
-		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
-		rule := android.NewRuleBuilder(pctx, ctx)
-		rule.Command().
-			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
-			Output(apisBackedbyOutputFile).
-			Flags(nativeLibNames)
-		rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
-		a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
-
-		var javaLibOrApkPath []android.Path
-		for _, f := range a.filesInfo {
-			if f.class == javaSharedLib || f.class == app {
-				javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
-			}
-		}
-		javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
-		javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
-		javaUsedByRule.Command().
-			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
-			BuiltTool("dexdeps").
-			Output(javaApiUsedbyOutputFile).
-			Inputs(javaLibOrApkPath)
-		javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
-		a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
-
-		bundleConfig := a.buildBundleConfig(ctx)
-
-		var abis []string
-		for _, target := range ctx.MultiTargets() {
-			if len(target.Arch.Abi) > 0 {
-				abis = append(abis, target.Arch.Abi[0])
-			}
-		}
-
-		abis = android.FirstUniqueStrings(abis)
-
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        apexBundleRule,
-			Input:       apexProtoFile,
-			Implicit:    bundleConfig,
-			Output:      a.bundleModuleFile,
-			Description: "apex bundle module",
-			Args: map[string]string{
-				"abi":    strings.Join(abis, "."),
-				"config": bundleConfig.String(),
-			},
-		})
-	} else { // zipApex
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        zipApexRule,
+			Rule:        DCLAApexRule,
 			Implicits:   implicitInputs,
 			Output:      unsignedOutputFile,
-			Description: "apex (" + apexType.name() + ")",
+			Description: "apex",
 			Args: map[string]string{
-				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":     imageDir.String(),
-				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      a.manifestPbOut.String(),
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
+			},
+		})
+	} else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        TrimmedApexRule,
+			Implicits:   implicitInputs,
+			Output:      unsignedOutputFile,
+			Description: "apex",
+			Args: map[string]string{
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
+				"libs_to_trim":     strings.Join(a.libs_to_trim(ctx), ","),
+			},
+		})
+	} else {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        apexRule,
+			Implicits:   implicitInputs,
+			Output:      unsignedOutputFile,
+			Description: "apex",
+			Args: map[string]string{
+				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":        imageDir.String(),
+				"copy_commands":    strings.Join(copyCommands, " && "),
+				"manifest":         a.manifestPbOut.String(),
+				"file_contexts":    fileContexts.String(),
+				"canned_fs_config": cannedFsConfig.String(),
+				"key":              a.privateKeyFile.String(),
+				"opt_flags":        strings.Join(optFlags, " "),
 			},
 		})
 	}
 
+	// TODO(jiyong): make the two rules below as separate functions
+	apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
+	bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
+	a.bundleModuleFile = bundleModuleFile
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        apexProtoConvertRule,
+		Input:       unsignedOutputFile,
+		Output:      apexProtoFile,
+		Description: "apex proto convert",
+	})
+
+	implicitInputs = append(implicitInputs, unsignedOutputFile)
+
+	// Run coverage analysis
+	apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        generateAPIsUsedbyApexRule,
+		Implicits:   implicitInputs,
+		Description: "coverage",
+		Output:      apisUsedbyOutputFile,
+		Args: map[string]string{
+			"image_dir": imageDir.String(),
+			"readelf":   "${config.ClangBin}/llvm-readelf",
+		},
+	})
+	a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
+
+	var nativeLibNames []string
+	for _, f := range a.filesInfo {
+		if f.class == nativeSharedLib {
+			nativeLibNames = append(nativeLibNames, f.stem())
+		}
+	}
+	apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
+	rb := android.NewRuleBuilder(pctx, ctx)
+	rb.Command().
+		Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
+		Output(apisBackedbyOutputFile).
+		Flags(nativeLibNames)
+	rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
+	a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+
+	var javaLibOrApkPath []android.Path
+	for _, f := range a.filesInfo {
+		if f.class == javaSharedLib || f.class == app {
+			javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
+		}
+	}
+	javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
+	javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+	javaUsedByRule.Command().
+		Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+		BuiltTool("dexdeps").
+		Output(javaApiUsedbyOutputFile).
+		Inputs(javaLibOrApkPath)
+	javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+	a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
+
+	bundleConfig := a.buildBundleConfig(ctx)
+
+	var abis []string
+	for _, target := range ctx.MultiTargets() {
+		if len(target.Arch.Abi) > 0 {
+			abis = append(abis, target.Arch.Abi[0])
+		}
+	}
+
+	abis = android.FirstUniqueStrings(abis)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        apexBundleRule,
+		Input:       apexProtoFile,
+		Implicit:    bundleConfig,
+		Output:      a.bundleModuleFile,
+		Description: "apex bundle module",
+		Args: map[string]string{
+			"abi":    strings.Join(abis, "."),
+			"config": bundleConfig.String(),
+		},
+	})
+
 	////////////////////////////////////////////////////////////////////////////////////
 	// Step 4: Sign the APEX using signapk
 	signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
@@ -878,6 +857,10 @@
 		args["outCommaList"] = signedOutputFile.String()
 	}
 	var validations android.Paths
+	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
+	if !a.testApex && a.SocSpecific() {
+		validations = append(validations, runApexVintfFragmentsValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
+	}
 	// TODO(b/279688635) deapexer supports [ext4]
 	if suffix == imageApexSuffix && ext4 == a.payloadFsType {
 		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
@@ -987,21 +970,12 @@
 }
 
 func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
-	if !a.primaryApexType {
-		return
-	}
-
 	if a.properties.IsCoverageVariant {
 		// Otherwise, we will have duplicated rules for coverage and
 		// non-coverage variants of the same APEX
 		return
 	}
 
-	if ctx.Host() {
-		// No need to generate dependency info for host variant
-		return
-	}
-
 	depInfos := android.DepNameToDepInfoMap{}
 	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
 		if from.Name() == to.Name() {
@@ -1141,6 +1115,32 @@
 	return cannedFsConfig.OutputPath
 }
 
+func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexLinkerconfigValidationRule,
+		Input:  apexFile,
+		Output: timestamp,
+		Args: map[string]string{
+			"image_dir": imageDir.String(),
+		},
+	})
+	return timestamp
+}
+
+func runApexVintfFragmentsValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+	timestamp := android.PathForModuleOut(ctx, "apex_vintf_fragments_validation.timestamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   apexVintfFragmentsValidationRule,
+		Input:  apexFile,
+		Output: timestamp,
+		Args: map[string]string{
+			"image_dir": imageDir.String(),
+		},
+	})
+	return timestamp
+}
+
 // Runs apex_sepolicy_tests
 //
 // $ deapexer list -Z {apex_file} > {file_contexts}
diff --git a/apex/key.go b/apex/key.go
index 3010d76..65e739a 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -60,7 +60,7 @@
 func ApexKeyFactory() android.Module {
 	module := &apexKey{}
 	module.AddProperties(&module.properties)
-	android.InitAndroidArchModule(module, android.HostAndDeviceDefault, android.MultilibCommon)
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitBazelModule(module)
 	return module
 }
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 3509e6c..1a90c3a 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -235,6 +235,7 @@
 					entries.SetString("LOCAL_MODULE_STEM", p.installFilename)
 					entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile)
 					entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String())
+					entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", p.compatSymlinks.Strings()...)
 					entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable())
 					entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...)
 					p.addRequiredModules(entries)
@@ -781,10 +782,10 @@
 	p.initApexFilesForAndroidMk(ctx)
 
 	// in case that prebuilt_apex replaces source apex (using prefer: prop)
-	p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx, true)
+	p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx)
 	// or that prebuilt_apex overrides other apexes (using overrides: prop)
 	for _, overridden := range p.prebuiltCommonProperties.Overrides {
-		p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+		p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
 	}
 
 	if p.installable() {
@@ -876,12 +877,7 @@
 		srcs = append(srcs, *e.Set)
 	}
 
-	var sanitizers []string
-	if ctx.Host() {
-		sanitizers = ctx.Config().SanitizeHost()
-	} else {
-		sanitizers = ctx.Config().SanitizeDevice()
-	}
+	sanitizers := ctx.Config().SanitizeDevice()
 
 	if android.InList("address", sanitizers) && e.Sanitized.Address.Set != nil {
 		srcs = append(srcs, *e.Sanitized.Address.Set)
@@ -1006,10 +1002,10 @@
 	}
 
 	// in case that apex_set replaces source apex (using prefer: prop)
-	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx, true)
+	a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
 	// or that apex_set overrides other apexes (using overrides: prop)
 	for _, overridden := range a.prebuiltCommonProperties.Overrides {
-		a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx, true)...)
+		a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
 	}
 }
 
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index f94e50f..40d0581 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -97,7 +97,7 @@
 
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/classpaths/systemserverclasspath.pb",
 		"javalib/foo.jar",
 		"javalib/bar.jar",
@@ -105,7 +105,7 @@
 		"javalib/baz.jar",
 	})
 
-	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{
 		`myapex.key`,
 		`mysystemserverclasspathfragment`,
 	})
@@ -157,11 +157,11 @@
 		}
 	`)
 
-	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		"javalib/foo.jar",
 	})
 
-	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{
 		`myapex.key`,
 		`mysystemserverclasspathfragment`,
 	})
@@ -361,7 +361,7 @@
 
 	ctx := result.TestContext
 
-	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{
 		"etc/classpaths/systemserverclasspath.pb",
 		"javalib/foo.jar",
 		"javalib/bar.jar",
diff --git a/apex/vndk.go b/apex/vndk.go
index 095e89d..26c60ed 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -80,6 +80,10 @@
 			// config targets the 'current' VNDK (see `vndkVersion`).
 			ab.Disable()
 		}
+		if proptools.String(ab.vndkProperties.Vndk_version) != "" &&
+			apiLevel.GreaterThanOrEqualTo(android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())) {
+			ab.Disable()
+		}
 	}
 }
 
@@ -103,19 +107,15 @@
 		}
 	} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
 		vndkVersion := proptools.StringDefault(a.vndkProperties.Vndk_version, "current")
-		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion)...)
+		mctx.AddDependency(mctx.Module(), prebuiltTag, cc.VndkLibrariesTxtModules(vndkVersion, mctx)...)
 	}
 }
 
 // name is module.BaseModuleName() which is used as LOCAL_MODULE_NAME and also LOCAL_OVERRIDES_*
-func makeCompatSymlinks(name string, ctx android.ModuleContext, primaryApex bool) (symlinks android.InstallPaths) {
+func makeCompatSymlinks(name string, ctx android.ModuleContext) (symlinks android.InstallPaths) {
 	// small helper to add symlink commands
 	addSymlink := func(target string, dir android.InstallPath, linkName string) {
-		if primaryApex {
-			symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
-		} else {
-			symlinks = append(symlinks, dir.Join(ctx, linkName))
-		}
+		symlinks = append(symlinks, ctx.InstallAbsoluteSymlink(dir, linkName, target))
 	}
 
 	// TODO(b/142911355): [VNDK APEX] Fix hard-coded references to /system/lib/vndk
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 21526c3..2b86e53 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -51,10 +51,11 @@
 	`+vndkLibrariesTxtFiles("current"),
 		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 			variables.DeviceVndkVersion = proptools.StringPtr("")
+			variables.KeepVndk = proptools.BoolPtr(true)
 		}),
 	)
 	// VNDK-Lite contains only core variants of VNDK-Sp libraries
-	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common_image", []string{
+	ensureExactContents(t, ctx, "com.android.vndk.current", "android_common", []string{
 		"lib/libvndksp.so",
 		"lib/libc++.so",
 		"lib64/libvndksp.so",
@@ -109,7 +110,7 @@
 		}
 
 		// VNDK APEX doesn't create apex variant
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
@@ -121,7 +122,7 @@
 			}),
 		)
 
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 	})
 
@@ -133,10 +134,10 @@
 			}),
 		)
 
-		files := getFiles(t, ctx, "com.android.vndk.current", "android_common_image")
+		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
 
-		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov_image")
+		files = getFiles(t, ctx, "com.android.vndk.current", "android_common_cov")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared_cov/libfoo.so")
 	})
 }
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 3428328..c355712 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,15 +17,15 @@
 import (
 	"crypto/sha256"
 	"encoding/base64"
+	"encoding/json"
 	"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"
@@ -119,6 +119,11 @@
 	// If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment
 	// and run the mixed build action there
 	ShouldRunInSbox bool
+	// A list of files to add as implicit deps to the outputs of this BuildStatement.
+	// Unlike most properties in BuildStatement, these paths must be relative to the root of
+	// the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
+	ImplicitDeps []string
+	IsExecutable bool
 }
 
 // A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -172,6 +177,21 @@
 		if err != nil {
 			return nil, err
 		}
+		if artifact.IsTreeArtifact &&
+			!strings.HasPrefix(artifactPath, "bazel-out/io_bazel_rules_go/") &&
+			!strings.HasPrefix(artifactPath, "bazel-out/rules_java_builtin/") {
+			// Since we're using ninja as an executor, we can't use tree artifacts. Ninja only
+			// considers a file/directory "dirty" when it's mtime changes. Directories' mtimes will
+			// only change when a file in the directory is added/removed, but not when files in
+			// the directory are changed, or when files in subdirectories are changed/added/removed.
+			// Bazel handles this by walking the directory and generating a hash for it after the
+			// action runs, which we would have to do as well if we wanted to support these
+			// artifacts in mixed builds.
+			//
+			// However, there are some bazel built-in rules that use tree artifacts. Allow those,
+			// but keep in mind that they'll have incrementality issues.
+			return nil, fmt.Errorf("tree artifacts are currently not supported in mixed builds: " + artifactPath)
+		}
 		artifactIdToPath[artifactId(artifact.Id)] = artifactPath
 	}
 
@@ -459,7 +479,7 @@
 // escapes the args received from aquery and creates a command string
 func commandString(actionEntry *analysis_v2_proto.Action) string {
 	switch actionEntry.Mnemonic {
-	case "GoCompilePkg":
+	case "GoCompilePkg", "GoStdlib":
 		argsEscaped := []string{}
 		for _, arg := range actionEntry.Arguments {
 			if arg == "" {
@@ -556,6 +576,7 @@
 		Mnemonic:          actionEntry.Mnemonic,
 		InputDepsetHashes: depsetHashes,
 		FileContents:      actionEntry.FileContents,
+		IsExecutable:      actionEntry.IsExecutable,
 	}, nil
 }
 
@@ -581,6 +602,72 @@
 	}, nil
 }
 
+type bazelSandwichJson struct {
+	Target         string   `json:"target"`
+	DependOnTarget *bool    `json:"depend_on_target,omitempty"`
+	ImplicitDeps   []string `json:"implicit_deps"`
+}
+
+func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+	outputPaths, depfile, err := a.getOutputPaths(actionEntry)
+	if err != nil {
+		return nil, err
+	}
+	if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 {
+		return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths)
+	}
+	target := actionEntry.UnresolvedSymlinkTarget
+	if target == "" {
+		return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one")
+	}
+	if filepath.Clean(target) != target {
+		return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target)
+	}
+	if strings.HasPrefix(target, "/") {
+		return nil, fmt.Errorf("no absolute symlinks allowed: %s", target)
+	}
+
+	out := outputPaths[0]
+	outDir := filepath.Dir(out)
+	var implicitDeps []string
+	if strings.HasPrefix(target, "bazel_sandwich:") {
+		j := bazelSandwichJson{}
+		err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j)
+		if err != nil {
+			return nil, err
+		}
+		if proptools.BoolDefault(j.DependOnTarget, true) {
+			implicitDeps = append(implicitDeps, j.Target)
+		}
+		implicitDeps = append(implicitDeps, j.ImplicitDeps...)
+		dotDotsToReachCwd := ""
+		if outDir != "." {
+			dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1)
+		}
+		target = proptools.ShellEscapeIncludingSpaces(j.Target)
+		target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target
+	} else {
+		target = proptools.ShellEscapeIncludingSpaces(target)
+	}
+
+	outDir = proptools.ShellEscapeIncludingSpaces(outDir)
+	out = proptools.ShellEscapeIncludingSpaces(out)
+	// Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+	command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target)
+	symlinkPaths := outputPaths[:]
+
+	buildStatement := &BuildStatement{
+		Command:      command,
+		Depfile:      depfile,
+		OutputPaths:  outputPaths,
+		Env:          actionEntry.EnvironmentVariables,
+		Mnemonic:     actionEntry.Mnemonic,
+		SymlinkPaths: symlinkPaths,
+		ImplicitDeps: implicitDeps,
+	}
+	return buildStatement, nil
+}
+
 func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
 	outputPaths, depfile, err := a.getOutputPaths(actionEntry)
 	if err != nil {
@@ -690,6 +777,8 @@
 		return a.fileWriteActionBuildStatement(actionEntry)
 	case "SymlinkTree":
 		return a.symlinkTreeActionBuildStatement(actionEntry)
+	case "UnresolvedSymlink":
+		return a.unresolvedSymlinkActionBuildStatement(actionEntry)
 	}
 
 	if len(actionEntry.Arguments) < 1 {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 19a584f..32c87a0 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -357,9 +357,11 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	if expected := 1; len(actual) != expected {
 		t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+		return
 	}
 
 	bs := actual[0]
@@ -544,6 +546,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -756,9 +759,11 @@
 	actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	if expected := 2; len(actualBuildStatements) != expected {
 		t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
+		return
 	}
 
 	expectedDepsetFiles := [][]string{
@@ -859,6 +864,7 @@
 
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -907,6 +913,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -1017,6 +1024,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 
 	expectedBuildStatements := []*BuildStatement{
@@ -1088,6 +1096,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -1126,6 +1135,7 @@
 	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
 	if err != nil {
 		t.Errorf("Unexpected error %q", err)
+		return
 	}
 	assertBuildStatements(t, []*BuildStatement{
 		&BuildStatement{
@@ -1136,6 +1146,126 @@
 	}, actual)
 }
 
+func TestUnresolvedSymlink(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "symlink/target"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+	}}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwich(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+		ImplicitDeps: []string{"target/product/emulator_x86_64/system"},
+	}}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) {
+	const inputString = `
+{
+ "artifacts": [
+   { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+   "target_id": 1,
+   "action_key": "x",
+   "mnemonic": "UnresolvedSymlink",
+   "configuration_id": 1,
+   "output_ids": [1],
+   "primary_output_id": 1,
+   "execution_platform": "//build/bazel/platforms:linux_x86_64",
+   "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+   { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+	data, err := JsonToActionGraphContainer(inputString)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+	if err != nil {
+		t.Errorf("Unexpected error %q", err)
+		return
+	}
+	assertBuildStatements(t, []*BuildStatement{{
+		Command:      "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+		OutputPaths:  []string{"path/to/symlink"},
+		Mnemonic:     "UnresolvedSymlink",
+		SymlinkPaths: []string{"path/to/symlink"},
+		// Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here
+		ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"},
+	}}, actual)
+}
+
 func assertError(t *testing.T, err error, expected string) {
 	t.Helper()
 	if err == nil {
@@ -1201,6 +1331,9 @@
 	if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
 		return "SymlinkPaths"
 	}
+	if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) {
+		return "ImplicitDeps"
+	}
 	if first.Depfile != second.Depfile {
 		return "Depfile"
 	}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index d962a1d..1fe8442 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -39,7 +39,7 @@
 
 	// Targets in arch.go
 	osArchAndroidArm        = "android_arm"
-	osArchAndroidArm64      = "android_arm64"
+	OsArchAndroidArm64      = "android_arm64"
 	osArchAndroidRiscv64    = "android_riscv64"
 	osArchAndroidX86        = "android_x86"
 	osArchAndroidX86_64     = "android_x86_64"
@@ -67,7 +67,7 @@
 
 	ConditionsDefaultSelectKey = "//conditions:default"
 
-	productVariableBazelPackage = "//build/bazel/product_variables"
+	productVariableBazelPackage = "//build/bazel/product_config/config_settings"
 
 	AndroidAndInApex = "android-in_apex"
 	AndroidPlatform  = "system"
@@ -76,6 +76,8 @@
 	NonApex = "non_apex"
 
 	ErrorproneDisabled = "errorprone_disabled"
+	// TODO: b/294868620 - Remove when completing the bug
+	SanitizersEnabled = "sanitizers_enabled"
 )
 
 func PowerSetWithoutEmptySet[T any](items []T) [][]T {
@@ -168,7 +170,7 @@
 
 	platformOsArchMap = map[string]string{
 		osArchAndroidArm:           "//build/bazel/platforms/os_arch:android_arm",
-		osArchAndroidArm64:         "//build/bazel/platforms/os_arch:android_arm64",
+		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",
@@ -223,6 +225,12 @@
 		ErrorproneDisabled:         "//build/bazel/rules/java/errorprone:errorprone_globally_disabled",
 		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
 	}
+
+	// TODO: b/294868620 - Remove when completing the bug
+	sanitizersEnabledMap = map[string]string{
+		SanitizersEnabled:          "//build/bazel/rules/cc:sanitizers_enabled",
+		ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
+	}
 )
 
 // basic configuration types
@@ -237,6 +245,8 @@
 	osAndInApex
 	inApex
 	errorProneDisabled
+	// TODO: b/294868620 - Remove when completing the bug
+	sanitizersEnabled
 )
 
 func osArchString(os string, arch string) string {
@@ -253,6 +263,8 @@
 		osAndInApex:        "os_in_apex",
 		inApex:             "in_apex",
 		errorProneDisabled: "errorprone_disabled",
+		// TODO: b/294868620 - Remove when completing the bug
+		sanitizersEnabled: "sanitizers_enabled",
 	}[ct]
 }
 
@@ -287,6 +299,11 @@
 		if _, ok := errorProneMap[config]; !ok {
 			panic(fmt.Errorf("Unknown errorprone config: %s", config))
 		}
+	// TODO: b/294868620 - Remove when completing the bug
+	case sanitizersEnabled:
+		if _, ok := sanitizersEnabledMap[config]; !ok {
+			panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config))
+		}
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
 	}
@@ -318,6 +335,9 @@
 		return inApexMap[config]
 	case errorProneDisabled:
 		return errorProneMap[config]
+	// TODO: b/294868620 - Remove when completing the bug
+	case sanitizersEnabled:
+		return sanitizersEnabledMap[config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
 	}
@@ -338,6 +358,9 @@
 	InApexAxis = ConfigurationAxis{configurationType: inApex}
 
 	ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled}
+
+	// TODO: b/294868620 - Remove when completing the bug
+	SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled}
 )
 
 // ProductVariableConfigurationAxis returns an axis for the given product variable
diff --git a/bazel/properties.go b/bazel/properties.go
index 15af09b..9c63bc0 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -194,14 +194,7 @@
 // UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
 // the slice in a sorted order.
 func UniqueSortedBazelLabels(originalLabels []Label) []Label {
-	uniqueLabelsSet := make(map[Label]bool)
-	for _, l := range originalLabels {
-		uniqueLabelsSet[l] = true
-	}
-	var uniqueLabels []Label
-	for l, _ := range uniqueLabelsSet {
-		uniqueLabels = append(uniqueLabels, l)
-	}
+	uniqueLabels := FirstUniqueBazelLabels(originalLabels)
 	sort.SliceStable(uniqueLabels, func(i, j int) bool {
 		return uniqueLabels[i].Label < uniqueLabels[j].Label
 	})
@@ -210,13 +203,13 @@
 
 func FirstUniqueBazelLabels(originalLabels []Label) []Label {
 	var labels []Label
-	found := make(map[Label]bool, len(originalLabels))
+	found := make(map[string]bool, len(originalLabels))
 	for _, l := range originalLabels {
-		if _, ok := found[l]; ok {
+		if _, ok := found[l.Label]; ok {
 			continue
 		}
 		labels = append(labels, l)
-		found[l] = true
+		found[l.Label] = true
 	}
 	return labels
 }
@@ -288,6 +281,41 @@
 	return result
 }
 
+// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
+// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
+// repetitions.
+func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
+	var result LabelListAttribute
+	result.Value = FirstUniqueBazelLabelList(attr.Value)
+	if attr.HasConfigurableValues() {
+		result.ConfigurableValues = make(configurableLabelLists)
+	}
+	for axis, configToLabels := range attr.ConfigurableValues {
+		for c, l := range configToLabels {
+			result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
+		}
+	}
+
+	return result
+}
+
+// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
+// axis/configuration.
+func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
+	var result LabelListAttribute
+	result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
+	if haystack.HasConfigurableValues() {
+		result.ConfigurableValues = make(configurableLabelLists)
+	}
+	for axis, configToLabels := range haystack.ConfigurableValues {
+		for haystackConfig, haystackLabels := range configToLabels {
+			result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
+		}
+	}
+
+	return result
+}
+
 type Attribute interface {
 	HasConfigurableValues() bool
 }
@@ -398,7 +426,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		la.Value = &value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if la.ConfigurableValues == nil {
 			la.ConfigurableValues = make(configurableLabels)
 		}
@@ -414,7 +442,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return la.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		return la.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -484,7 +512,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		ba.Value = value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if ba.ConfigurableValues == nil {
 			ba.ConfigurableValues = make(configurableBools)
 		}
@@ -631,7 +659,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return ba.Value
-	case arch, os, osArch, productVariables, osAndInApex:
+	case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
 		if v, ok := ba.ConfigurableValues[axis][config]; ok {
 			return &v
 		} else {
@@ -766,7 +794,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		lla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		if lla.ConfigurableValues == nil {
 			lla.ConfigurableValues = make(configurableLabelLists)
 		}
@@ -782,7 +810,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return lla.Value
-	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
 		return lla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
@@ -1140,7 +1168,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sa.Value = str
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, sanitizersEnabled:
 		if sa.ConfigurableValues == nil {
 			sa.ConfigurableValues = make(configurableStrings)
 		}
@@ -1156,7 +1184,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sa.Value
-	case arch, os, osArch, productVariables:
+	case arch, os, osArch, productVariables, sanitizersEnabled:
 		if v, ok := sa.ConfigurableValues[axis][config]; ok {
 			return v
 		} else {
@@ -1346,7 +1374,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		sla.Value = list
-	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		if sla.ConfigurableValues == nil {
 			sla.ConfigurableValues = make(configurableStringLists)
 		}
@@ -1362,7 +1390,7 @@
 	switch axis.configurationType {
 	case noConfig:
 		return sla.Value
-	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled:
+	case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
 		return sla.ConfigurableValues[axis][config]
 	default:
 		panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
index c56d11f..751cb8b 100644
--- a/bazel/properties_test.go
+++ b/bazel/properties_test.go
@@ -33,8 +33,12 @@
 				{Label: "b"},
 				{Label: "a"},
 				{Label: "c"},
+				// namespaces
+				{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
+				{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace
 			},
 			expectedUniqueLabels: []Label{
+				{Label: "//foo:bar", OriginalModuleName: "bar"},
 				{Label: "a"},
 				{Label: "b"},
 				{Label: "c"},
@@ -125,6 +129,63 @@
 		}
 	}
 }
+
+func TestSubtractBazelLabelListAttribute(t *testing.T) {
+	testCases := []struct {
+		haystack LabelListAttribute
+		needle   LabelListAttribute
+		expected LabelListAttribute
+	}{
+		{
+			haystack: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "a", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
+						"x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
+					},
+				},
+			},
+			needle: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"d", "a"},
+					[]string{"x", "y2", "z2"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
+						"x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
+					},
+				},
+			},
+			expected: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"b", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"arm_2"}, []string{}),
+						"x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
+					},
+				},
+				ForceSpecifyEmptyList: false,
+				EmitEmptyList:         false,
+				Prepend:               false,
+			},
+		},
+	}
+	for _, tc := range testCases {
+		got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
+		if !reflect.DeepEqual(tc.expected, got) {
+			t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
+		}
+	}
+}
+
 func TestFirstUniqueBazelLabelList(t *testing.T) {
 	testCases := []struct {
 		originalLabelList       LabelList
@@ -137,6 +198,9 @@
 					{Label: "b"},
 					{Label: "a"},
 					{Label: "c"},
+					// namespaces
+					{Label: "//foo:bar", OriginalModuleName: "bar"},       // when referenced from foo namespace
+					{Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace
 				},
 				Excludes: []Label{
 					{Label: "x"},
@@ -150,6 +214,7 @@
 					{Label: "a"},
 					{Label: "b"},
 					{Label: "c"},
+					{Label: "//foo:bar", OriginalModuleName: "bar"},
 				},
 				Excludes: []Label{
 					{Label: "x"},
@@ -167,6 +232,46 @@
 	}
 }
 
+func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
+	testCases := []struct {
+		originalLabelList       LabelListAttribute
+		expectedUniqueLabelList LabelListAttribute
+	}{
+		{
+			originalLabelList: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "a", "c"},
+					[]string{"x", "x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
+						"x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
+					},
+				},
+			},
+			expectedUniqueLabelList: LabelListAttribute{
+				Value: makeLabelList(
+					[]string{"a", "b", "c"},
+					[]string{"x", "y", "z"},
+				),
+				ConfigurableValues: configurableLabelLists{
+					ArchConfigurationAxis: labelListSelectValues{
+						"arm": makeLabelList([]string{"1", "2"}, []string{}),
+						"x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
+					},
+				},
+			},
+		},
+	}
+	for _, tc := range testCases {
+		actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
+		if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
+			t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
+		}
+	}
+}
+
 func TestUniqueSortedBazelLabelList(t *testing.T) {
 	testCases := []struct {
 		originalLabelList       LabelList
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index f889693..b675e5e 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -32,6 +32,7 @@
         "soong-genrule",
         "soong-linkerconfig",
         "soong-python",
+        "soong-rust",
         "soong-sh",
         "soong-shared",
         "soong-starlark-format",
@@ -46,6 +47,7 @@
         "apex_conversion_test.go",
         "apex_key_conversion_test.go",
         "build_conversion_test.go",
+        "bp2build_product_config_test.go",
         "bzl_conversion_test.go",
         "cc_binary_conversion_test.go",
         "cc_library_conversion_test.go",
@@ -60,7 +62,6 @@
         "cc_test_conversion_test.go",
         "cc_yasm_conversion_test.go",
         "conversion_test.go",
-        "droidstubs_conversion_test.go",
         "filegroup_conversion_test.go",
         "genrule_conversion_test.go",
         "gensrcs_conversion_test.go",
@@ -81,7 +82,12 @@
         "python_binary_conversion_test.go",
         "python_library_conversion_test.go",
         "python_test_conversion_test.go",
+        "rust_binary_conversion_test.go",
+        "rust_library_conversion_test.go",
+        "rust_proc_macro_conversion_test.go",
+        "rust_protobuf_conversion_test.go",
         "sh_conversion_test.go",
+        "sh_test_conversion_test.go",
         "soong_config_module_type_conversion_test.go",
     ],
     pluginFor: [
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 09d9dc1..13bb167 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -35,21 +35,21 @@
 			"res/res.png":                  "",
 			"manifest/AndroidManifest.xml": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-        name: "TestLib",
-        srcs: ["lib.java"],
-        arch: {
-			arm: {
-				srcs: ["arm.java"],
-			},
-			x86: {
-				srcs: ["x86.java"],
-			}
+	name: "TestLib",
+	srcs: ["lib.java"],
+	arch: {
+		arm: {
+			srcs: ["arm.java"],
 		},
-        manifest: "manifest/AndroidManifest.xml",
-        static_libs: ["static_lib_dep"],
-        java_version: "7",
+		x86: {
+			srcs: ["x86.java"],
+		}
+	},
+	manifest: "manifest/AndroidManifest.xml",
+	static_libs: ["static_lib_dep"],
+	sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -66,12 +66,9 @@
 					"resource_files": `["res/res.png"]`,
 					"deps":           `[":static_lib_dep"]`,
 					"exports":        `[":static_lib_dep"]`,
-					"java_version":   `"7"`,
+					"sdk_version":    `"current"`, // use as default
 				}),
-			MakeNeverlinkDuplicateTargetWithAttrs(
-				"android_library",
-				"TestLib",
-				AttrNameToString{"java_version": `"7"`}),
+			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
 }
 
@@ -85,12 +82,13 @@
 			"res/res.png":         "",
 			"AndroidManifest.xml": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "lib_dep") + `
 android_library {
-        name: "TestLib",
-        srcs: [],
-        manifest: "AndroidManifest.xml",
-        libs: ["lib_dep"],
+	name: "TestLib",
+	srcs: [],
+	manifest: "AndroidManifest.xml",
+	libs: ["lib_dep"],
+	sdk_version: "current",
 }
 `,
 		ExpectedErr:          fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
@@ -115,12 +113,13 @@
 			// Bazel's aar_import can only export *_import targets, so we expect
 			// only "static_import_dep" in exports, but both "static_lib_dep" and
 			// "static_import_dep" in deps
-			Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") +
-				simpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") +
+				SimpleModuleDoNotConvertBp2build("android_library_import", "static_import_dep") + `
 android_library_import {
         name: "TestImport",
         aars: ["import.aar"],
         static_libs: ["static_lib_dep", "static_import_dep"],
+    sdk_version: "current",
 }
 `,
 			ExpectedBazelTargets: []string{
@@ -133,7 +132,8 @@
         ":static_lib_dep",
         ":static_import_dep",
     ]`,
-						"exports": `[":static_import_dep"]`,
+						"exports":     `[":static_import_dep"]`,
+						"sdk_version": `"current"`, // use as default
 					},
 				),
 				MakeNeverlinkDuplicateTarget("android_library", "TestImport"),
@@ -153,9 +153,10 @@
 		},
 		Blueprint: `
 android_library {
-        name: "TestLib",
-        srcs: ["a.java", "b.kt"],
-        common_srcs: ["c.kt"],
+	name: "TestLib",
+	srcs: ["a.java", "b.kt"],
+	common_srcs: ["c.kt"],
+	sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -170,6 +171,7 @@
 					"common_srcs":    `["c.kt"]`,
 					"manifest":       `"AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -186,9 +188,10 @@
 		},
 		Blueprint: `
 android_library {
-        name: "TestLib",
-        srcs: ["a.java", "b.kt"],
-        kotlincflags: ["-flag1", "-flag2"],
+	name: "TestLib",
+	srcs: ["a.java", "b.kt"],
+	kotlincflags: ["-flag1", "-flag2"],
+	sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -206,6 +209,7 @@
     ]`,
 					"manifest":       `"AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
diff --git a/bp2build/android_app_conversion_test.go b/bp2build/android_app_conversion_test.go
index d1b4d40..0d206b0 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -40,12 +40,18 @@
 			"app.java":            "",
 			"res/res.png":         "",
 			"AndroidManifest.xml": "",
+			"assets/asset.png":    "",
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        srcs: ["app.java"],
-        sdk_version: "current",
+		name: "TestApp",
+		srcs: ["app.java"],
+		sdk_version: "current",
+		optimize: {
+			shrink: true,
+			optimize: true,
+			obfuscate: true,
+		},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -54,6 +60,8 @@
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
 				"sdk_version":    `"current"`,
+				"assets":         `["assets/asset.png"]`,
+				"assets_dir":     `"assets"`,
 			}),
 		}})
 }
@@ -68,19 +76,29 @@
 			"resa/res.png":                 "",
 			"resb/res.png":                 "",
 			"manifest/AndroidManifest.xml": "",
+			"assets_/asset.png":            "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_app", "static_lib_dep") + `
 android_app {
-        name: "TestApp",
-        srcs: ["app.java"],
-        sdk_version: "current",
-        package_name: "com.google",
-        resource_dirs: ["resa", "resb"],
-        manifest: "manifest/AndroidManifest.xml",
-        static_libs: ["static_lib_dep"],
-        java_version: "7",
-        certificate: "foocert",
-        required: ["static_lib_dep"],
+	name: "TestApp",
+	srcs: ["app.java"],
+	sdk_version: "current",
+	package_name: "com.google",
+	resource_dirs: ["resa", "resb"],
+	manifest: "manifest/AndroidManifest.xml",
+	static_libs: ["static_lib_dep"],
+	java_version: "7",
+	certificate: "foocert",
+	required: ["static_lib_dep"],
+	asset_dirs: ["assets_"],
+	optimize: {
+		enabled: true,
+		optimize: false,
+		proguard_flags_files: ["proguard.flags"],
+		shrink: false,
+		obfuscate: false,
+		ignore_warnings: true,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -91,11 +109,21 @@
         "resa/res.png",
         "resb/res.png",
     ]`,
+				"assets":           `["assets_/asset.png"]`,
+				"assets_dir":       `"assets_"`,
 				"custom_package":   `"com.google"`,
 				"deps":             `[":static_lib_dep"]`,
 				"java_version":     `"7"`,
 				"sdk_version":      `"current"`,
 				"certificate_name": `"foocert"`,
+				"proguard_specs": `[
+        "proguard.flags",
+        ":TestApp_proguard_flags",
+    ]`,
+			}),
+			MakeBazelTarget("genrule", "TestApp_proguard_flags", AttrNameToString{
+				"outs": `["TestApp_proguard.flags"]`,
+				"cmd":  `"echo -ignorewarning -dontshrink -dontoptimize -dontobfuscate > $(OUTS)"`,
 			}),
 		}})
 }
@@ -113,16 +141,19 @@
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        sdk_version: "current",
-        arch: {
-			arm: {
-				srcs: ["arm.java"],
-			},
-			x86: {
-				srcs: ["x86.java"],
-			}
+	name: "TestApp",
+	sdk_version: "current",
+	arch: {
+		arm: {
+			srcs: ["arm.java"],
+		},
+		x86: {
+			srcs: ["x86.java"],
 		}
+	},
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -135,6 +166,7 @@
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
 				"sdk_version":    `"current"`,
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -145,10 +177,14 @@
 		ModuleTypeUnderTest:        "android_app",
 		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
 		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
 android_app {
-        name: "TestApp",
-        certificate: ":foocert",
+	name: "TestApp",
+	certificate: ":foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -156,6 +192,8 @@
 				"certificate":    `":foocert"`,
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
+				"sdk_version":    `"current"`, // use as default
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -170,8 +208,12 @@
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        certificate: "foocert",
+	name: "TestApp",
+	certificate: "foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -179,6 +221,8 @@
 				"certificate":    `"foocert"`,
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
+				"sdk_version":    `"current"`, // use as default
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -193,8 +237,12 @@
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        certificate: "foocert",
+	name: "TestApp",
+	certificate: "foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -202,6 +250,8 @@
 				"certificate_name": `"foocert"`,
 				"manifest":         `"AndroidManifest.xml"`,
 				"resource_files":   `[]`,
+				"sdk_version":      `"current"`, // use as default
+				"optimize":         `False`,
 			}),
 		}})
 }
@@ -212,22 +262,23 @@
 		ModuleTypeUnderTest:        "android_app",
 		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
 		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("java_library", "barLib") + `
 android_app {
-        name: "foo",
-				libs: ["barLib"]
-}
-java_library{
-       name: "barLib",
+	name: "foo",
+	libs: ["barLib"],
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
 			MakeBazelTarget("android_binary", "foo", AttrNameToString{
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
 				"deps":           `[":barLib-neverlink"]`,
+				"sdk_version":    `"current"`, // use as default
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -240,21 +291,21 @@
 		Filesystem: map[string]string{
 			"res/res.png": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("filegroup", "foocert") +
+			SimpleModuleDoNotConvertBp2build("java_library", "barLib") + `
 android_app {
-        name: "foo",
-        srcs: ["a.java", "b.kt"],
-        certificate: ":foocert",
-        manifest: "fooManifest.xml",
-        libs: ["barLib"]
-}
-java_library{
-      name:   "barLib",
+	name: "foo",
+	srcs: ["a.java", "b.kt"],
+	certificate: ":foocert",
+	manifest: "fooManifest.xml",
+	libs: ["barLib"],
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
 			MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
 				"srcs": `[
         "a.java",
@@ -263,11 +314,14 @@
 				"manifest":       `"fooManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
 				"deps":           `[":barLib-neverlink"]`,
+				"sdk_version":    `"current"`, // use as default
 			}),
 			MakeBazelTarget("android_binary", "foo", AttrNameToString{
 				"deps":        `[":foo_kt"]`,
 				"certificate": `":foocert"`,
 				"manifest":    `"fooManifest.xml"`,
+				"sdk_version": `"current"`, // use as default
+				"optimize":    `False`,
 			}),
 		}})
 }
@@ -280,33 +334,37 @@
 		Filesystem: map[string]string{
 			"res/res.png": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: `
 android_app {
-        name: "foo",
-        srcs: ["a.java"],
-        common_srcs: ["b.kt"],
-        certificate: "foocert",
-        manifest: "fooManifest.xml",
-        libs:        ["barLib"],
+	name: "foo",
+	srcs: ["a.java"],
+	common_srcs: ["b.kt"],
+	manifest: "fooManifest.xml",
+	libs:        ["barLib"],
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 java_library{
-      name:   "barLib",
+	name:   "barLib",
+	bazel_module: { bp2build_available: false },
 }
 `,
 		ExpectedBazelTargets: []string{
-			MakeBazelTarget("java_library", "barLib", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "barLib"),
 			MakeBazelTarget("android_library", "foo_kt", AttrNameToString{
 				"srcs":           `["a.java"]`,
 				"common_srcs":    `["b.kt"]`,
 				"manifest":       `"fooManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
 				"deps":           `[":barLib-neverlink"]`,
+				"sdk_version":    `"current"`, // use as default
 			}),
 			MakeBazelTarget("android_binary", "foo", AttrNameToString{
-				"deps":             `[":foo_kt"]`,
-				"certificate_name": `"foocert"`,
-				"manifest":         `"fooManifest.xml"`,
+				"deps":        `[":foo_kt"]`,
+				"manifest":    `"fooManifest.xml"`,
+				"sdk_version": `"current"`, // use as default
+				"optimize":    `False`,
 			}),
 		}})
 }
@@ -319,13 +377,16 @@
 		Filesystem: map[string]string{
 			"res/res.png": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: `
 android_app {
-        name: "foo",
-        srcs: ["a.java", "b.kt"],
-        certificate: ":foocert",
-        manifest: "fooManifest.xml",
-        kotlincflags: ["-flag1", "-flag2"],
+	name: "foo",
+	srcs: ["a.java", "b.kt"],
+	manifest: "fooManifest.xml",
+	kotlincflags: ["-flag1", "-flag2"],
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -340,11 +401,13 @@
         "-flag1",
         "-flag2",
     ]`,
+				"sdk_version": `"current"`, // use as default
 			}),
 			MakeBazelTarget("android_binary", "foo", AttrNameToString{
 				"deps":        `[":foo_kt"]`,
-				"certificate": `":foocert"`,
 				"manifest":    `"fooManifest.xml"`,
+				"sdk_version": `"current"`,
+				"optimize":    `False`,
 			}),
 		}})
 }
@@ -355,13 +418,16 @@
 		ModuleTypeUnderTest:        "android_app",
 		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
 		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: `
 android_app {
-        name: "foo",
-        sdk_version: "current",
-        min_sdk_version: "24",
-        max_sdk_version: "30",
-        target_sdk_version: "29",
+	name: "foo",
+	sdk_version: "current",
+	min_sdk_version: "24",
+	max_sdk_version: "30",
+	target_sdk_version: "29",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -374,6 +440,7 @@
         "targetSdkVersion": "29",
     }`,
 				"sdk_version": `"current"`,
+				"optimize":    `False`,
 			}),
 		}})
 }
@@ -384,10 +451,13 @@
 		ModuleTypeUnderTest:        "android_app",
 		ModuleTypeUnderTestFactory: java.AndroidAppFactory,
 		Filesystem:                 map[string]string{},
-		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
+		Blueprint: `
 android_app {
-        name: "foo",
-        sdk_version: "30",
+	name: "foo",
+	sdk_version: "30",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -399,6 +469,7 @@
         "targetSdkVersion": "30",
     }`,
 				"sdk_version": `"30"`,
+				"optimize":    `False`,
 			}),
 		}})
 }
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 84c7ea2..5aed4ad 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -1263,7 +1263,7 @@
 	file_contexts: ":com.android.apogee-file_contexts",
 	certificate: ":com.android.apogee.certificate",
 }
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
+` + SimpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"certificate":   `":com.android.apogee.certificate"`,
@@ -1299,7 +1299,7 @@
 	binaries: ["bar"],
 	native_shared_libs: ["foo"],
 }
-` + simpleModuleDoNotConvertBp2build("filegroup", "myapex-file_contexts"),
+` + SimpleModuleDoNotConvertBp2build("filegroup", "myapex-file_contexts"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_binary", "bar", AttrNameToString{
 				"local_includes": `["."]`,
@@ -1356,7 +1356,7 @@
 	file_contexts: ":com.android.apogee-file_contexts",
 	certificate: "com.android.apogee.certificate",
 }
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
+` + SimpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee-file_contexts"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("apex", "com.android.apogee", AttrNameToString{
 				"certificate_name": `"com.android.apogee.certificate"`,
@@ -1555,7 +1555,7 @@
 				"file_contexts": `":foo-file_contexts"`,
 				"manifest":      `"apex_manifest.json"`,
 				"min_sdk_version": `select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
         "//conditions:default": "31",
     })`,
 				"package_name": `"pkg_name"`,
@@ -1564,7 +1564,7 @@
 				"file_contexts":  `":foo-file_contexts"`,
 				"manifest":       `"apex_manifest.json"`,
 				"min_sdk_version": `select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
         "//conditions:default": "31",
     })`,
 				"package_name": `"override_pkg_name"`,
diff --git a/bp2build/apex_key_conversion_test.go b/bp2build/apex_key_conversion_test.go
index f9a68c9..8f6e843 100644
--- a/bp2build/apex_key_conversion_test.go
+++ b/bp2build/apex_key_conversion_test.go
@@ -47,8 +47,9 @@
 }
 `,
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key": `"com.android.apogee.pem"`,
-			"public_key":  `"com.android.apogee.avbpubkey"`,
+			"private_key":            `"com.android.apogee.pem"`,
+			"public_key":             `"com.android.apogee.avbpubkey"`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
 		}),
 		}})
 }
@@ -69,8 +70,9 @@
 }
 `,
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key_name": `"com.android.apogee.pem"`,
-			"public_key_name":  `"com.android.apogee.avbpubkey"`,
+			"private_key_name":       `"com.android.apogee.pem"`,
+			"public_key_name":        `"com.android.apogee.avbpubkey"`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
 		}),
 		}})
 }
@@ -87,11 +89,12 @@
         public_key: ":com.android.apogee.avbpubkey",
         private_key: ":com.android.apogee.pem",
 }
-` + simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.avbpubkey") +
-			simpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.pem"),
+` + SimpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.avbpubkey") +
+			SimpleModuleDoNotConvertBp2build("filegroup", "com.android.apogee.pem"),
 		ExpectedBazelTargets: []string{MakeBazelTargetNoRestrictions("apex_key", "com.android.apogee.key", AttrNameToString{
-			"private_key": `":com.android.apogee.pem"`,
-			"public_key":  `":com.android.apogee.avbpubkey"`,
+			"private_key":            `":com.android.apogee.pem"`,
+			"public_key":             `":com.android.apogee.avbpubkey"`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
 		}),
 		}})
 }
diff --git a/bp2build/api_domain_conversion_test.go b/bp2build/api_domain_conversion_test.go
deleted file mode 100644
index 224008f..0000000
--- a/bp2build/api_domain_conversion_test.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/cc"
-)
-
-func registerApiDomainModuleTypes(ctx android.RegistrationContext) {
-	android.RegisterApiDomainBuildComponents(ctx)
-	cc.RegisterNdkModuleTypes(ctx)
-	cc.RegisterLibraryBuildComponents(ctx)
-}
-
-func TestApiDomainContributionsTest(t *testing.T) {
-	bp := `
-	api_domain {
-		name: "system",
-		cc_api_contributions: [
-			"libfoo.ndk",
-			"libbar",
-		],
-	}
-	`
-	fs := map[string]string{
-		"libfoo/Android.bp": `
-		ndk_library {
-			name: "libfoo",
-		}
-		`,
-		"libbar/Android.bp": `
-		cc_library {
-			name: "libbar",
-		}
-		`,
-	}
-	expectedBazelTarget := MakeBazelTargetNoRestrictions(
-		"api_domain",
-		"system",
-		AttrNameToString{
-			"cc_api_contributions": `[
-        "//libfoo:libfoo.ndk.contribution",
-        "//libbar:libbar.contribution",
-    ]`,
-			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-		},
-	)
-	RunApiBp2BuildTestCase(t, registerApiDomainModuleTypes, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-		Filesystem:           fs,
-	})
-}
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index cfe52db..5f7b382 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,7 +15,6 @@
 package bp2build
 
 import (
-	"android/soong/starlark_import"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -24,6 +23,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/shared"
+	"android/soong/starlark_import"
 )
 
 func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
@@ -67,6 +67,8 @@
 // writing .bzl files that are equivalent to Android.bp files that are capable
 // of being built with Bazel.
 func Codegen(ctx *CodegenContext) *CodegenMetrics {
+	ctx.Context().BeginEvent("Codegen")
+	defer ctx.Context().EndEvent("Codegen")
 	// This directory stores BUILD files that could be eventually checked-in.
 	bp2buildDir := android.PathForOutput(ctx, "bp2build")
 
@@ -79,7 +81,10 @@
 		fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
 		os.Exit(1)
 	}
-	bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
+	var bp2buildFiles []BazelFile
+	ctx.Context().EventHandler.Do("CreateBazelFile", func() {
+		bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
+	})
 	injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
 	if err != nil {
 		fmt.Printf("%s\n", err.Error())
@@ -111,7 +116,7 @@
 func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
 	var ret []BazelFile
 
-	productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx)
+	productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index c8067af..20355d7 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -1,20 +1,25 @@
 package bp2build
 
 import (
-	"android/soong/android"
-	"android/soong/starlark_import"
 	"encoding/json"
 	"fmt"
 	"os"
 	"path/filepath"
+	"reflect"
 	"strings"
 
+	"android/soong/android"
+	"android/soong/android/soongconfig"
+	"android/soong/starlark_import"
+
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 	"go.starlark.net/starlark"
 )
 
 func CreateProductConfigFiles(
-	ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
+	ctx *CodegenContext,
+	metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
 	cfg := &ctx.config
 	targetProduct := "unknown"
 	if cfg.HasDeviceProduct() {
@@ -41,6 +46,15 @@
 		return nil, nil, err
 	}
 
+	// 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"`
+		}
+	})
+
 	// TODO(b/249685973): the name is product_config_platforms because product_config
 	// was already used for other files. Deduplicate them.
 	currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant)
@@ -50,11 +64,24 @@
 		"{VARIANT}", targetBuildVariant,
 		"{PRODUCT_FOLDER}", currentProductFolder)
 
-	platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables)
+	platformMappingContent, err := platformMappingContent(
+		productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"),
+		&productVariables,
+		ctx.Config().Bp2buildSoongConfigDefinitions,
+		metrics.convertedModulePathMap)
 	if err != nil {
 		return nil, nil, err
 	}
 
+	productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
+	if err != nil {
+		return nil, nil, err
+	}
+	productsForTesting := android.SortedKeys(productsForTestingMap)
+	for i := range productsForTesting {
+		productsForTesting[i] = fmt.Sprintf("  \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
+	}
+
 	injectionDirFiles := []BazelFile{
 		newFile(
 			currentProductFolder,
@@ -96,6 +123,7 @@
 android_product(
     name = "mixed_builds_product-{VARIANT}",
     soong_variables = _soong_variables,
+    extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
 )
 `)),
 		newFile(
@@ -108,9 +136,8 @@
 # currently lunched product, they should all be listed here
 product_labels = [
   "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
-  "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
-]
-`)),
+  "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}",
+`)+strings.Join(productsForTesting, "\n")+"\n]\n"),
 		newFile(
 			"product_config_platforms",
 			"common.bazelrc",
@@ -119,6 +146,7 @@
 build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
 
 build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
+build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86
 build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
 build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
 build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
@@ -136,6 +164,11 @@
 			productReplacer.Replace(`
 build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
 `)),
+		newFile(
+			"cc_toolchain",
+			"ndk_libs.bzl",
+			fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", ")),
+		),
 	}
 	bp2buildDirFiles := []BazelFile{
 		newFile(
@@ -146,21 +179,39 @@
 	return injectionDirFiles, bp2buildDirFiles, nil
 }
 
-func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables) (string, error) {
+func platformMappingContent(
+	mainProductLabel string,
+	mainProductVariables *android.ProductVariables,
+	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+	convertedModulePathMap map[string]string) (string, error) {
 	productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
 	if err != nil {
 		return "", err
 	}
-	result := "platforms:\n"
-	result += platformMappingSingleProduct(mainProductLabel, mainProductVariables)
+	var result strings.Builder
+
+	mergedConvertedModulePathMap := make(map[string]string)
+	for k, v := range convertedModulePathMap {
+		mergedConvertedModulePathMap[k] = v
+	}
+	additionalModuleNamesToPackages, err := starlark_import.GetStarlarkValue[map[string]string]("additional_module_names_to_packages")
+	if err != nil {
+		return "", err
+	}
+	for k, v := range additionalModuleNamesToPackages {
+		mergedConvertedModulePathMap[k] = v
+	}
+
+	result.WriteString("platforms:\n")
+	platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	for product, productVariablesStarlark := range productsForTesting {
 		productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
 		if err != nil {
 			return "", err
 		}
-		result += platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables)
+		platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
 	}
-	return result, nil
+	return result.String(), nil
 }
 
 var bazelPlatformSuffixes = []string{
@@ -177,42 +228,194 @@
 	"_windows_x86_64",
 }
 
-func platformMappingSingleProduct(label string, productVariables *android.ProductVariables) string {
-	buildSettings := ""
-	buildSettings += fmt.Sprintf("    --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride))
-	buildSettings += fmt.Sprintf("    --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ","))
-	buildSettings += fmt.Sprintf("    --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ","))
-	buildSettings += fmt.Sprintf("    --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true))
-	buildSettings += fmt.Sprintf("    --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ","))
-	result := ""
-	for _, suffix := range bazelPlatformSuffixes {
-		result += "  " + label + suffix + "\n" + buildSettings
+func platformMappingSingleProduct(
+	label string,
+	productVariables *android.ProductVariables,
+	soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+	convertedModulePathMap map[string]string,
+	result *strings.Builder) {
+	targetBuildVariant := "user"
+	if proptools.Bool(productVariables.Eng) {
+		targetBuildVariant = "eng"
+	} else if proptools.Bool(productVariables.Debuggable) {
+		targetBuildVariant = "userdebug"
 	}
-	return result
+
+	platform_sdk_version := -1
+	if productVariables.Platform_sdk_version != nil {
+		platform_sdk_version = *productVariables.Platform_sdk_version
+	}
+
+	defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup"
+	if proptools.String(productVariables.DefaultAppCertificate) != "" {
+		defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory"
+	}
+
+	for _, suffix := range bazelPlatformSuffixes {
+		result.WriteString("  ")
+		result.WriteString(label)
+		result.WriteString(suffix)
+		result.WriteString("\n")
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_broken_incorrect_partition_images=%t\n", productVariables.BuildBrokenIncorrectPartitionImages))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:default_app_certificate_filegroup=%s\n", defaultAppCertificateFilegroup))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.DevicePageSizeAgnostic)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:device_platform=%s\n", label))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:memtag_heap_exclude_paths=%s\n", strings.Join(productVariables.MemtagHeapExcludePaths, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:memtag_heap_async_include_paths=%s\n", strings.Join(productVariables.MemtagHeapAsyncIncludePaths, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:memtag_heap_sync_include_paths=%s\n", strings.Join(productVariables.MemtagHeapSyncIncludePaths, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:platform_sdk_version=%d\n", platform_sdk_version))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:treble_linker_namespaces=%t\n", proptools.Bool(productVariables.Treble_linker_namespaces)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
+		result.WriteString(fmt.Sprintf("    --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
+
+		for _, override := range productVariables.CertificateOverrides {
+			parts := strings.SplitN(override, ":", 2)
+			if apexPath, ok := convertedModulePathMap[parts[0]]; ok {
+				if overrideCertPath, ok := convertedModulePathMap[parts[1]]; ok {
+					result.WriteString(fmt.Sprintf("    --%s:%s_certificate_override=%s:%s\n", apexPath, parts[0], overrideCertPath, parts[1]))
+				}
+			}
+		}
+
+		for namespace, namespaceContents := range productVariables.VendorVars {
+			for variable, value := range namespaceContents {
+				key := namespace + "__" + variable
+				_, hasBool := soongConfigDefinitions.BoolVars[key]
+				_, hasString := soongConfigDefinitions.StringVars[key]
+				_, hasValue := soongConfigDefinitions.ValueVars[key]
+				if !hasBool && !hasString && !hasValue {
+					// Not all soong config variables are defined in Android.bp files. For example,
+					// prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard
+					// way, that causes them to be present in the soong.variables file but not
+					// defined in an Android.bp file. There's also nothing stopping you from setting
+					// a variable in make that doesn't exist in soong. We only generate build
+					// settings for the ones that exist in soong, so skip all others.
+					continue
+				}
+				if hasBool && hasString || hasBool && hasValue || hasString && hasValue {
+					panic(fmt.Sprintf("Soong config variable %s:%s appears to be of multiple types. bool? %t, string? %t, value? %t", namespace, variable, hasBool, hasString, hasValue))
+				}
+				if hasBool {
+					// Logic copied from soongConfig.Bool()
+					value = strings.ToLower(value)
+					if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" {
+						value = "true"
+					} else {
+						value = "false"
+					}
+				}
+				result.WriteString(fmt.Sprintf("    --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value))
+			}
+		}
+	}
 }
 
 func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
-	var err error
 	result := android.ProductVariables{}
-	result.ApexGlobalMinSdkVersionOverride, err = starlark_import.UnmarshalNoneable[string](in["ApexGlobalMinSdkVersionOverride"])
-	if err != nil {
-		return result, err
+	productVarsReflect := reflect.ValueOf(&result).Elem()
+	for i := 0; i < productVarsReflect.NumField(); i++ {
+		field := productVarsReflect.Field(i)
+		fieldType := productVarsReflect.Type().Field(i)
+		name := fieldType.Name
+		if name == "BootJars" || name == "ApexBootJars" || name == "VendorSnapshotModules" ||
+			name == "RecoverySnapshotModules" {
+			// These variables have more complicated types, and we don't need them right now
+			continue
+		}
+		if _, ok := in[name]; ok {
+			if name == "VendorVars" {
+				vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name])
+				if err != nil {
+					return result, err
+				}
+				field.Set(reflect.ValueOf(vendorVars))
+				continue
+			}
+			switch field.Type().Kind() {
+			case reflect.Bool:
+				val, err := starlark_import.Unmarshal[bool](in[name])
+				if err != nil {
+					return result, err
+				}
+				field.SetBool(val)
+			case reflect.String:
+				val, err := starlark_import.Unmarshal[string](in[name])
+				if err != nil {
+					return result, err
+				}
+				field.SetString(val)
+			case reflect.Slice:
+				if field.Type().Elem().Kind() != reflect.String {
+					return result, fmt.Errorf("slices of types other than strings are unimplemented")
+				}
+				val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
+				if err != nil {
+					return result, err
+				}
+				field.Set(val)
+			case reflect.Pointer:
+				switch field.Type().Elem().Kind() {
+				case reflect.Bool:
+					val, err := starlark_import.UnmarshalNoneable[bool](in[name])
+					if err != nil {
+						return result, err
+					}
+					field.Set(reflect.ValueOf(val))
+				case reflect.String:
+					val, err := starlark_import.UnmarshalNoneable[string](in[name])
+					if err != nil {
+						return result, err
+					}
+					field.Set(reflect.ValueOf(val))
+				case reflect.Int:
+					val, err := starlark_import.UnmarshalNoneable[int](in[name])
+					if err != nil {
+						return result, err
+					}
+					field.Set(reflect.ValueOf(val))
+				default:
+					return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
+				}
+			default:
+				return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
+			}
+		}
 	}
-	result.CFIIncludePaths, err = starlark_import.Unmarshal[[]string](in["CFIIncludePaths"])
-	if err != nil {
-		return result, err
-	}
-	result.CFIExcludePaths, err = starlark_import.Unmarshal[[]string](in["CFIExcludePaths"])
-	if err != nil {
-		return result, err
-	}
-	result.EnableCFI, err = starlark_import.UnmarshalNoneable[bool](in["EnableCFI"])
-	if err != nil {
-		return result, err
-	}
-	result.DeviceAbi, err = starlark_import.Unmarshal[[]string](in["DeviceAbi"])
-	if err != nil {
-		return result, err
-	}
+
+	result.Native_coverage = proptools.BoolPtr(
+		proptools.Bool(result.GcovCoverage) ||
+			proptools.Bool(result.ClangCoverage))
+
 	return result, nil
 }
diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go
new file mode 100644
index 0000000..02d83b4
--- /dev/null
+++ b/bp2build/bp2build_product_config_test.go
@@ -0,0 +1,89 @@
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/starlark_import"
+	"encoding/json"
+	"reflect"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+	"go.starlark.net/starlark"
+)
+
+func createStarlarkValue(t *testing.T, code string) starlark.Value {
+	t.Helper()
+	result, err := starlark.ExecFile(&starlark.Thread{}, "main.bzl", "x = "+code, nil)
+	if err != nil {
+		t.Error(err)
+	}
+	return result["x"]
+}
+
+func createStarlarkProductVariablesMap(t *testing.T, code string) map[string]starlark.Value {
+	t.Helper()
+	rawValue := createStarlarkValue(t, code)
+	value, err := starlark_import.Unmarshal[map[string]starlark.Value](rawValue)
+	if err != nil {
+		t.Error(err)
+	}
+	return value
+}
+
+func TestStarlarkMapToProductVariables(t *testing.T) {
+	thirty := 30
+	cases := []struct {
+		starlark string
+		result   android.ProductVariables
+	}{
+		{
+			starlark: `{"CompressedApex": True}`,
+			result:   android.ProductVariables{CompressedApex: proptools.BoolPtr(true)},
+		},
+		{
+			starlark: `{"ApexGlobalMinSdkVersionOverride": "Tiramisu"}`,
+			result:   android.ProductVariables{ApexGlobalMinSdkVersionOverride: proptools.StringPtr("Tiramisu")},
+		},
+		{
+			starlark: `{"ProductManufacturer": "Google"}`,
+			result:   android.ProductVariables{ProductManufacturer: "Google"},
+		},
+		{
+			starlark: `{"Unbundled_build_apps": ["app1", "app2"]}`,
+			result:   android.ProductVariables{Unbundled_build_apps: []string{"app1", "app2"}},
+		},
+		{
+			starlark: `{"Platform_sdk_version": 30}`,
+			result:   android.ProductVariables{Platform_sdk_version: &thirty},
+		},
+		{
+			starlark: `{"HostFakeSnapshotEnabled": True}`,
+			result:   android.ProductVariables{HostFakeSnapshotEnabled: true},
+		},
+	}
+
+	for _, testCase := range cases {
+		productVariables, err := starlarkMapToProductVariables(createStarlarkProductVariablesMap(t,
+			testCase.starlark))
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		testCase.result.Native_coverage = proptools.BoolPtr(false)
+		if !reflect.DeepEqual(testCase.result, productVariables) {
+			expected, err := json.Marshal(testCase.result)
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			actual, err := json.Marshal(productVariables)
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			expectedStr := string(expected)
+			actualStr := string(actual)
+			t.Errorf("expected %q, but got %q", expectedStr, actualStr)
+		}
+	}
+}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 0e6596b..9060363 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -29,6 +29,7 @@
 	"android/soong/bazel"
 	"android/soong/starlark_fmt"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
@@ -94,16 +95,16 @@
 // statements (use LoadStatements for that), since the targets are usually not
 // adjacent to the load statements at the top of the BUILD file.
 func (targets BazelTargets) String() string {
-	var res string
+	var res strings.Builder
 	for i, target := range targets {
 		if target.ruleClass != "package" {
-			res += target.content
+			res.WriteString(target.content)
 		}
 		if i != len(targets)-1 {
-			res += "\n\n"
+			res.WriteString("\n\n")
 		}
 	}
-	return res
+	return res.String()
 }
 
 // LoadStatements return the string representation of the sorted and deduplicated
@@ -174,9 +175,6 @@
 	// This mode is used for discovering and introspecting the existing Soong
 	// module graph.
 	QueryView
-
-	// ApiBp2build - generate BUILD files for API contribution targets
-	ApiBp2build
 )
 
 type unconvertedDepsMode int
@@ -195,8 +193,6 @@
 		return "Bp2Build"
 	case QueryView:
 		return "QueryView"
-	case ApiBp2build:
-		return "ApiBp2build"
 	default:
 		return fmt.Sprintf("%d", mode)
 	}
@@ -353,7 +349,104 @@
 	Importpath             bazel.StringAttribute
 	Srcs                   bazel.LabelListAttribute
 	Deps                   bazel.LabelListAttribute
+	Data                   bazel.LabelListAttribute
 	Target_compatible_with bazel.LabelListAttribute
+
+	// attributes for the dynamically generated go_test target
+	Embed bazel.LabelListAttribute
+}
+
+type goTestProperties struct {
+	name           string
+	dir            string
+	testSrcs       []string
+	linuxTestSrcs  []string
+	darwinTestSrcs []string
+	testData       []string
+	// Name of the target that should be compiled together with the test
+	embedName string
+}
+
+// Creates a go_test target for bootstrap_go_package / blueprint_go_binary
+func generateBazelTargetsGoTest(ctx *android.Context, goModulesMap nameToGoLibraryModule, gp goTestProperties) (BazelTarget, error) {
+	ca := android.CommonAttributes{
+		Name: gp.name,
+	}
+	ga := goAttributes{
+		Srcs: goSrcLabels(ctx.Config(), gp.dir, gp.testSrcs, gp.linuxTestSrcs, gp.darwinTestSrcs),
+		Data: goSrcLabels(ctx.Config(), gp.dir, gp.testData, []string{}, []string{}),
+		Embed: bazel.MakeLabelListAttribute(
+			bazel.MakeLabelList(
+				[]bazel.Label{bazel.Label{Label: ":" + gp.embedName}},
+			),
+		),
+		Target_compatible_with: targetNotCompatibleWithAndroid(),
+	}
+
+	libTest := goBazelTarget{
+		targetName:            gp.name,
+		targetPackage:         gp.dir,
+		bazelRuleClass:        "go_test",
+		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
+		bazelAttributes:       []interface{}{&ca, &ga},
+	}
+	return generateBazelTarget(ctx, libTest)
+}
+
+// TODO - b/288491147: testSrcs of certain bootstrap_go_package/blueprint_go_binary are not hermetic and depend on
+// testdata checked into the filesystem.
+// Denylist the generation of go_test targets for these Soong modules.
+// The go_library/go_binary will still be generated, since those are hermitic.
+var (
+	goTestsDenylist = []string{
+		"android-archive-zip",
+		"bazel_notice_gen",
+		"blueprint-bootstrap-bpdoc",
+		"blueprint-microfactory",
+		"blueprint-pathtools",
+		"bssl_ar",
+		"compliance_checkmetadata",
+		"compliance_checkshare",
+		"compliance_dumpgraph",
+		"compliance_dumpresolutions",
+		"compliance_listshare",
+		"compliance-module",
+		"compliancenotice_bom",
+		"compliancenotice_shippedlibs",
+		"compliance_rtrace",
+		"compliance_sbom",
+		"golang-protobuf-internal-fuzz-jsonfuzz",
+		"golang-protobuf-internal-fuzz-textfuzz",
+		"golang-protobuf-internal-fuzz-wirefuzz",
+		"htmlnotice",
+		"protoc-gen-go",
+		"rbcrun-module",
+		"spdx-tools-builder",
+		"spdx-tools-builder2v1",
+		"spdx-tools-builder2v2",
+		"spdx-tools-builder2v3",
+		"spdx-tools-idsearcher",
+		"spdx-tools-spdx-json",
+		"spdx-tools-utils",
+		"soong-ui-build",
+		"textnotice",
+		"xmlnotice",
+	}
+)
+
+func testOfGoPackageIsIncompatible(g *bootstrap.GoPackage) bool {
+	return android.InList(g.Name(), goTestsDenylist) ||
+		// Denylist tests of soong_build
+		// Theses tests have a guard that prevent usage outside a test environment
+		// The guard (`ensureTestOnly`) looks for a `-test` in os.Args, which is present in soong's gotestrunner, but missing in `b test`
+		g.IsPluginFor("soong_build") ||
+		// soong-android is a dep of soong_build
+		// This dependency is created by soong_build by listing it in its deps explicitly in Android.bp, and not via `plugin_for` in `soong-android`
+		g.Name() == "soong-android"
+}
+
+func testOfGoBinaryIsIncompatible(g *bootstrap.GoBinary) bool {
+	return android.InList(g.Name(), goTestsDenylist)
 }
 
 func generateBazelTargetsGoPackage(ctx *android.Context, g *bootstrap.GoPackage, goModulesMap nameToGoLibraryModule) ([]BazelTarget, []error) {
@@ -390,12 +483,33 @@
 		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
 		bazelAttributes:       []interface{}{&ca, &ga},
 	}
-	// TODO - b/284483729: Create go_test target from testSrcs
-	libTarget, err := generateBazelTarget(ctx, lib)
-	if err != nil {
-		return []BazelTarget{}, []error{err}
+	retTargets := []BazelTarget{}
+	var retErrs []error
+	if libTarget, err := generateBazelTarget(ctx, lib); err == nil {
+		retTargets = append(retTargets, libTarget)
+	} else {
+		retErrs = []error{err}
 	}
-	return []BazelTarget{libTarget}, nil
+
+	// If the library contains test srcs, create an additional go_test target
+	if !testOfGoPackageIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
+		gp := goTestProperties{
+			name:           g.Name() + "-test",
+			dir:            ctx.ModuleDir(g),
+			testSrcs:       g.TestSrcs(),
+			linuxTestSrcs:  g.LinuxTestSrcs(),
+			darwinTestSrcs: g.DarwinTestSrcs(),
+			testData:       g.TestData(),
+			embedName:      g.Name(), // embed the source go_library in the test so that its .go files are included in the compilation unit
+		}
+		if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
+			retTargets = append(retTargets, libTestTarget)
+		} else {
+			retErrs = append(retErrs, err)
+		}
+	}
+
+	return retTargets, retErrs
 }
 
 type goLibraryModule struct {
@@ -440,6 +554,9 @@
 		Name: g.Name(),
 	}
 
+	retTargets := []BazelTarget{}
+	var retErrs []error
+
 	// For this bootstrap_go_package dep chain,
 	// A --> B --> C ( ---> depends on)
 	// Soong provides the convenience of only listing B as deps of A even if a src file of A imports C
@@ -450,12 +567,70 @@
 	// bp2build does not have sufficient info on whether C is a direct dep of A or not, so for now collect all transitive deps and add them to deps
 	transitiveDeps := transitiveGoDeps(g.Deps(), goModulesMap)
 
+	goSource := ""
+	// If the library contains test srcs, create an additional go_test target
+	// The go_test target will embed a go_source containining the source .go files it tests
+	if !testOfGoBinaryIsIncompatible(g) && (len(g.TestSrcs()) > 0 || len(g.LinuxTestSrcs()) > 0 || len(g.DarwinTestSrcs()) > 0) {
+		// Create a go_source containing the source .go files of go_library
+		// This target will be an `embed` of the go_binary and go_test
+		goSource = g.Name() + "-source"
+		ca := android.CommonAttributes{
+			Name: goSource,
+		}
+		ga := goAttributes{
+			Srcs:                   goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
+			Deps:                   goDepLabels(transitiveDeps, goModulesMap),
+			Target_compatible_with: targetNotCompatibleWithAndroid(),
+		}
+		libTestSource := goBazelTarget{
+			targetName:            goSource,
+			targetPackage:         ctx.ModuleDir(g),
+			bazelRuleClass:        "go_source",
+			bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
+			bazelAttributes:       []interface{}{&ca, &ga},
+		}
+		if libSourceTarget, err := generateBazelTarget(ctx, libTestSource); err == nil {
+			retTargets = append(retTargets, libSourceTarget)
+		} else {
+			retErrs = append(retErrs, err)
+		}
+
+		// Create a go_test target
+		gp := goTestProperties{
+			name:           g.Name() + "-test",
+			dir:            ctx.ModuleDir(g),
+			testSrcs:       g.TestSrcs(),
+			linuxTestSrcs:  g.LinuxTestSrcs(),
+			darwinTestSrcs: g.DarwinTestSrcs(),
+			testData:       g.TestData(),
+			// embed the go_source in the test
+			embedName: g.Name() + "-source",
+		}
+		if libTestTarget, err := generateBazelTargetsGoTest(ctx, goModulesMap, gp); err == nil {
+			retTargets = append(retTargets, libTestTarget)
+		} else {
+			retErrs = append(retErrs, err)
+		}
+
+	}
+
+	// Create a go_binary target
 	ga := goAttributes{
-		Srcs:                   goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs()),
 		Deps:                   goDepLabels(transitiveDeps, goModulesMap),
 		Target_compatible_with: targetNotCompatibleWithAndroid(),
 	}
 
+	// If the binary has testSrcs, embed the common `go_source`
+	if goSource != "" {
+		ga.Embed = bazel.MakeLabelListAttribute(
+			bazel.MakeLabelList(
+				[]bazel.Label{bazel.Label{Label: ":" + goSource}},
+			),
+		)
+	} else {
+		ga.Srcs = goSrcLabels(ctx.Config(), ctx.ModuleDir(g), g.Srcs(), g.LinuxSrcs(), g.DarwinSrcs())
+	}
+
 	bin := goBazelTarget{
 		targetName:            g.Name(),
 		targetPackage:         ctx.ModuleDir(g),
@@ -463,15 +638,19 @@
 		bazelRuleLoadLocation: "@io_bazel_rules_go//go:def.bzl",
 		bazelAttributes:       []interface{}{&ca, &ga},
 	}
-	// TODO - b/284483729: Create go_test target from testSrcs
-	binTarget, err := generateBazelTarget(ctx, bin)
-	if err != nil {
-		return []BazelTarget{}, []error{err}
+
+	if binTarget, err := generateBazelTarget(ctx, bin); err == nil {
+		retTargets = append(retTargets, binTarget)
+	} else {
+		retErrs = []error{err}
 	}
-	return []BazelTarget{binTarget}, nil
+
+	return retTargets, retErrs
 }
 
 func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
+	ctx.Context().BeginEvent("GenerateBazelTargets")
+	defer ctx.Context().EndEvent("GenerateBazelTargets")
 	buildFileToTargets := make(map[string]BazelTargets)
 
 	// Simple metrics tracking for bp2build
@@ -502,6 +681,9 @@
 			//
 			// 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
@@ -563,10 +745,12 @@
 				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
 				metrics.IncrementRuleClassCount("go_library")
+				metrics.AddConvertedModule(glib, "go_library", dir)
 			} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
 				targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
 				metrics.IncrementRuleClassCount("go_binary")
+				metrics.AddConvertedModule(gbin, "go_binary", dir)
 			} else {
 				metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
 					ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
@@ -585,10 +769,6 @@
 				errs = append(errs, err)
 			}
 			targets = append(targets, t)
-		case ApiBp2build:
-			if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-				targets, errs = generateBazelTargets(bpCtx, aModule)
-			}
 		default:
 			errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
 			return
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index e127fd5..4897566 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -640,7 +640,10 @@
 }`,
 			ExpectedBazelTargets: []string{
 				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
-					"target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
+					"target_compatible_with": `select({
+        "//build/bazel/product_config/config_settings:unbundled_build": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    })`,
 				}),
 			},
 		},
@@ -1740,7 +1743,7 @@
 			Description:                "Required into data test",
 			ModuleTypeUnderTest:        "filegroup",
 			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
 filegroup {
     name: "fg_foo",
     required: ["reqd"],
@@ -1756,7 +1759,7 @@
 			Description:                "Required into data test, cyclic self reference is filtered out",
 			ModuleTypeUnderTest:        "filegroup",
 			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
 filegroup {
     name: "fg_foo",
     required: ["reqd", "fg_foo"],
@@ -1772,8 +1775,8 @@
 			Description:                "Required via arch into data test",
 			ModuleTypeUnderTest:        "python_library",
 			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
-				simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
+				SimpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
 python_library {
     name: "fg_foo",
     arch: {
@@ -1806,7 +1809,7 @@
 				"data.bin": "",
 				"src.py":   "",
 			},
-			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("python_library", "reqd") + `
 python_library {
     name: "fg_foo",
     data: ["data.bin"],
@@ -1828,7 +1831,7 @@
 			Description:                "All props-to-attrs at once together test",
 			ModuleTypeUnderTest:        "filegroup",
 			ModuleTypeUnderTestFactory: android.FileGroupFactory,
-			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
+			Blueprint: SimpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
 filegroup {
     name: "fg_foo",
     required: ["reqd"],
@@ -1876,30 +1879,6 @@
 		})
 }
 
-func TestGenerateApiBazelTargets(t *testing.T) {
-	bp := `
-	custom {
-		name: "foo",
-		api: "foo.txt",
-	}
-	`
-	expectedBazelTarget := MakeBazelTarget(
-		"custom_api_contribution",
-		"foo",
-		AttrNameToString{
-			"api": `"foo.txt"`,
-		},
-	)
-	registerCustomModule := func(ctx android.RegistrationContext) {
-		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
-	}
-	RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: []string{expectedBazelTarget},
-		Description:          "Generating API contribution Bazel targets for custom module",
-	})
-}
-
 func TestGenerateConfigSetting(t *testing.T) {
 	bp := `
 	custom {
@@ -1946,3 +1925,46 @@
 	actual, _ := prettyPrintAttribute(lla, 0)
 	android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual)
 }
+
+// If CommonAttributes.Dir is set, the bazel target should be created in that dir
+func TestCreateBazelTargetInDifferentDir(t *testing.T) {
+	t.Parallel()
+	bp := `
+	custom {
+		name: "foo",
+		dir: "subdir",
+	}
+	`
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	// Check that foo is not created in root dir
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo is not created in root dir because it sets dir explicitly",
+		Blueprint:   bp,
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		ExpectedBazelTargets: []string{},
+	})
+	// Check that foo is created in `subdir`
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo is created in `subdir` because it sets dir explicitly",
+		Blueprint:   bp,
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		Dir: "subdir",
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("custom", "foo", AttrNameToString{}),
+		},
+	})
+	// Check that we cannot create target in different dir if it is does not an Android.bp
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Description: "foo cannot be created in `subdir` because it does not contain an Android.bp file",
+		Blueprint:   bp,
+		Dir:         "subdir",
+		ExpectedErr: fmt.Errorf("Cannot use ca.Dir to create a BazelTarget in dir: subdir since it does not contain an Android.bp file"),
+	})
+
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index fa1bf8a..402d4b0 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -94,6 +94,7 @@
         # bazel_module end
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -126,6 +127,7 @@
         "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -158,6 +160,7 @@
         "arch_paths_exclude": attr.string_list(),
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
+        "dir": attr.string(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -199,7 +202,7 @@
 			content: "irrelevant",
 		},
 	}
-	files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView)
+	files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
 
 	var actualSoongModuleBzl BazelFile
 	for _, f := range files {
diff --git a/bp2build/cc_binary_conversion_test.go b/bp2build/cc_binary_conversion_test.go
index d9a7860..3d3b860 100644
--- a/bp2build/cc_binary_conversion_test.go
+++ b/bp2build/cc_binary_conversion_test.go
@@ -276,7 +276,7 @@
     ],
     include_build_directory: false,
 }
-` + simpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
+` + SimpleModuleDoNotConvertBp2build("filegroup", "fg_foo"),
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
 				"srcs": `[
@@ -326,12 +326,12 @@
     export_generated_headers: ["export_generated_hdr"],
 }
 ` +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "static_dep") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "shared_dep") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep"),
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
 				"deps": `[
@@ -880,8 +880,15 @@
 }`,
 		targets: []testBazelTarget{
 			{"cc_binary", "foo", AttrNameToString{
+				"copts": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"],
+        "//conditions:default": [],
+    })`,
+				"additional_compiler_inputs": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"],
+        "//conditions:default": [],
+    })`,
 				"local_includes": `["."]`,
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
 			}},
 		},
 	})
@@ -1219,7 +1226,7 @@
 	runCcBinaryTestCase(t, ccBinaryBp2buildTestCase{
 		description: "cc_library_static system_shared_lib empty for linux_bionic variant",
 		blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+			SimpleModuleDoNotConvertBp2build("cc_library", "libc") + `
 
 cc_library {
     name: "libm",
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 490cd91..7af788e 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -94,7 +94,7 @@
 			"foo-dir/a.h":      "",
 		},
 		Blueprint: soongCcLibraryPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
+			SimpleModuleDoNotConvertBp2build("cc_library_headers", "some-headers") + `
 cc_library {
     name: "foo-lib",
     srcs: ["impl.cpp"],
@@ -176,7 +176,7 @@
 			"linker_cfi.h":             "",
 		},
 		Blueprint: soongCcLibraryPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
+			SimpleModuleDoNotConvertBp2build("cc_library_headers", "libc_headers") + `
 cc_library {
     name: "fake-ld-android",
     srcs: ["ld_android.cpp"],
@@ -457,24 +457,24 @@
     },
     include_build_directory: false,
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
-			simpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "static_dep_for_both") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "implementation_static_dep_for_both") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "whole_static_dep_for_both") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "not_explicitly_exported_whole_static_dep_for_both") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_static") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "shared_dep_for_both") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "implementation_shared_dep_for_both"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "a_bp2build_cc_library_static", AttrNameToString{
 				"copts": `[
@@ -1260,14 +1260,14 @@
         "//build/bazel/platforms/arch:arm": [],
         "//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte": [],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": [],
         "//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
     })`,
 			"implementation_dynamic_deps": `select({
         "//build/bazel/platforms/arch:arm": [],
         "//conditions:default": [":arm_shared_lib_excludes"],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
         "//conditions:default": [],
     })`,
 			"srcs_c": `["common.c"]`,
@@ -1275,7 +1275,7 @@
         "//build/bazel/platforms/arch:arm": [],
         "//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
         "//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"],
     })`,
 		}),
@@ -1307,7 +1307,7 @@
 `,
 		ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
 			"implementation_deps": `select({
-        "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_header_lib"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_header_lib"],
         "//conditions:default": [],
     })`,
 			"srcs_c":                 `["common.c"]`,
@@ -2394,7 +2394,7 @@
 	},
 	include_build_directory: false,
 }`,
-		ExpectedErr: fmt.Errorf("module \"foo\": Could not find the proto_library target for include dir: external/protobuf/abc"),
+		ExpectedErr: fmt.Errorf("module \"foo\": TODO: Add support for proto.include_dir: external/protobuf/abc. This directory does not contain an Android.bp file"),
 	})
 }
 
@@ -2434,12 +2434,18 @@
 			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 				"tags": `[
         "apex_available=//apex_available:anyapex",
         "manual",
     ]`,
+			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"actual": `"//.:a_fg_proto_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
 			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 			}),
@@ -2476,12 +2482,18 @@
 			}), MakeBazelTarget("cc_library_shared", "a", AttrNameToString{
 				"dynamic_deps":       `[":libprotobuf-cpp-lite"]`,
 				"whole_archive_deps": `[":a_cc_proto_lite"]`,
-			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_bp2build_converted", AttrNameToString{
+			}), MakeBazelTargetNoRestrictions("proto_library", "a_fg_proto_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 				"tags": `[
         "apex_available=//apex_available:anyapex",
         "manual",
     ]`,
+			}), MakeBazelTargetNoRestrictions("alias", "a_fg_proto_bp2build_converted", AttrNameToString{
+				"actual": `"//.:a_fg_proto_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
 			}), MakeBazelTargetNoRestrictions("filegroup", "a_fg_proto", AttrNameToString{
 				"srcs": `["a_fg.proto"]`,
 			}),
@@ -2537,10 +2549,10 @@
 		ModuleTypeUnderTest:        "cc_library",
 		ModuleTypeUnderTestFactory: cc.LibraryFactory,
 		Blueprint: soongCcProtoPreamble +
-			simpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
-			simpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
-			simpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
-			simpleModuleDoNotConvertBp2build("filegroup", "proto-srcs-d") + `
+			SimpleModuleDoNotConvertBp2build("filegroup", "a_fg_proto") +
+			SimpleModuleDoNotConvertBp2build("filegroup", "b_protos") +
+			SimpleModuleDoNotConvertBp2build("filegroup", "c-proto-srcs") +
+			SimpleModuleDoNotConvertBp2build("filegroup", "proto-srcs-d") + `
 cc_library {
 	name: "a",
 	srcs: [":a_fg_proto"],
@@ -2827,205 +2839,6 @@
 	)
 }
 
-func TestCcApiContributionsWithHdrs(t *testing.T) {
-	bp := `
-	cc_library {
-		name: "libfoo",
-		stubs: { symbol_file: "libfoo.map.txt", versions: ["28", "29", "current"] },
-		llndk: { symbol_file: "libfoo.map.txt", override_export_include_dirs: ["dir2"]},
-		export_include_dirs: ["dir1"],
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTarget(
-			"cc_api_library_headers",
-			"libfoo.module-libapi.headers",
-			AttrNameToString{
-				"export_includes": `["dir1"]`,
-			}),
-		MakeBazelTarget(
-			"cc_api_library_headers",
-			"libfoo.vendorapi.headers",
-			AttrNameToString{
-				"export_includes": `["dir2"]`,
-			}),
-		MakeBazelTarget(
-			"cc_api_contribution",
-			"libfoo.contribution",
-			AttrNameToString{
-				"api":          `"libfoo.map.txt"`,
-				"library_name": `"libfoo"`,
-				"api_surfaces": `[
-        "module-libapi",
-        "vendorapi",
-    ]`,
-				"hdrs": `[
-        ":libfoo.module-libapi.headers",
-        ":libfoo.vendorapi.headers",
-    ]`,
-			}),
-	}
-	RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-		Blueprint:            bp,
-		Description:          "cc API contributions to module-libapi and vendorapi",
-		ExpectedBazelTargets: expectedBazelTargets,
-	})
-}
-
-func TestCcApiSurfaceCombinations(t *testing.T) {
-	testCases := []struct {
-		bp                  string
-		expectedApi         string
-		expectedApiSurfaces string
-		description         string
-	}{
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				stubs: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi:         `"a.map.txt"`,
-			expectedApiSurfaces: `["module-libapi"]`,
-			description:         "Library that contributes to module-libapi",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				llndk: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi:         `"a.map.txt"`,
-			expectedApiSurfaces: `["vendorapi"]`,
-			description:         "Library that contributes to vendorapi",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				llndk: {symbol_file: "a.map.txt"},
-				stubs: {symbol_file: "a.map.txt"},
-			}`,
-			expectedApi: `"a.map.txt"`,
-			expectedApiSurfaces: `[
-        "module-libapi",
-        "vendorapi",
-    ]`,
-			description: "Library that contributes to module-libapi and vendorapi",
-		},
-	}
-	for _, testCase := range testCases {
-		expectedBazelTargets := []string{
-			MakeBazelTarget(
-				"cc_api_contribution",
-				"a.contribution",
-				AttrNameToString{
-					"library_name": `"a"`,
-					"hdrs":         `[]`,
-					"api":          testCase.expectedApi,
-					"api_surfaces": testCase.expectedApiSurfaces,
-				},
-			),
-		}
-		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-			Blueprint:            testCase.bp,
-			Description:          testCase.description,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	}
-}
-
-// llndk struct property in Soong provides users with several options to configure the exported include dirs
-// Test the generated bazel targets for the different configurations
-func TestCcVendorApiHeaders(t *testing.T) {
-	testCases := []struct {
-		bp                     string
-		expectedIncludes       string
-		expectedSystemIncludes string
-		description            string
-	}{
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					export_headers_as_system: true,
-				},
-			}
-			`,
-			expectedIncludes: "",
-			expectedSystemIncludes: `[
-        "base_system_include",
-        "include",
-    ]`,
-			description: "Headers are exported as system to API surface",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					override_export_include_dirs: ["llndk_include"],
-				},
-			}
-			`,
-			expectedIncludes:       `["llndk_include"]`,
-			expectedSystemIncludes: `["base_system_include"]`,
-			description:            "Non-system Headers are ovverriden before export to API surface",
-		},
-		{
-			bp: `
-			cc_library {
-				name: "a",
-				export_include_dirs: ["include"],
-				export_system_include_dirs: ["base_system_include"],
-				llndk: {
-					symbol_file: "a.map.txt",
-					override_export_include_dirs: ["llndk_include"],
-					export_headers_as_system: true,
-				},
-			}
-			`,
-			expectedIncludes: "", // includes are set to nil
-			expectedSystemIncludes: `[
-        "base_system_include",
-        "llndk_include",
-    ]`,
-			description: "System Headers are extended before export to API surface",
-		},
-	}
-	for _, testCase := range testCases {
-		attrs := AttrNameToString{}
-		if testCase.expectedIncludes != "" {
-			attrs["export_includes"] = testCase.expectedIncludes
-		}
-		if testCase.expectedSystemIncludes != "" {
-			attrs["export_system_includes"] = testCase.expectedSystemIncludes
-		}
-
-		expectedBazelTargets := []string{
-			MakeBazelTarget("cc_api_library_headers", "a.vendorapi.headers", attrs),
-			// Create a target for cc_api_contribution target
-			MakeBazelTarget("cc_api_contribution", "a.contribution", AttrNameToString{
-				"api":          `"a.map.txt"`,
-				"api_surfaces": `["vendorapi"]`,
-				"hdrs":         `[":a.vendorapi.headers"]`,
-				"library_name": `"a"`,
-			}),
-		}
-		RunApiBp2BuildTestCase(t, cc.RegisterLibraryBuildComponents, Bp2buildTestCase{
-			Blueprint:            testCase.bp,
-			ExpectedBazelTargets: expectedBazelTargets,
-		})
-	}
-}
-
 func TestCcLibraryStubsAcrossConfigsDuplicatesRemoved(t *testing.T) {
 	runCcLibraryTestCase(t, Bp2buildTestCase{
 		Description:                "stub target generation of the same lib across configs should not result in duplicates",
@@ -3054,7 +2867,6 @@
 		ExpectedBazelTargets: makeCcLibraryTargets("foolib", AttrNameToString{
 			"implementation_dynamic_deps": `select({
         "//build/bazel/rules/apex:foo": ["@api_surfaces//module-libapi/current:barlib"],
-        "//build/bazel/rules/apex:system": ["@api_surfaces//module-libapi/current:barlib"],
         "//conditions:default": [":barlib"],
     })`,
 			"local_includes": `["."]`,
@@ -3070,7 +2882,7 @@
 		Filesystem: map[string]string{
 			"bar.map.txt": "",
 		},
-		Blueprint: simpleModuleDoNotConvertBp2build("cc_library", "bazlib") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("cc_library", "bazlib") + `
 cc_library {
 	name: "quxlib",
 	stubs: { symbol_file: "bar.map.txt", versions: ["current"] },
@@ -3112,10 +2924,6 @@
             "@api_surfaces//module-libapi/current:barlib",
             "@api_surfaces//module-libapi/current:quxlib",
         ],
-        "//build/bazel/rules/apex:system": [
-            "@api_surfaces//module-libapi/current:barlib",
-            "@api_surfaces//module-libapi/current:quxlib",
-        ],
         "//conditions:default": [
             ":barlib",
             ":quxlib",
@@ -3729,10 +3537,10 @@
 		"baz-shared",
 	],
 }` +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "bar-static") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "baz-static") +
-			simpleModuleDoNotConvertBp2build("cc_library", "bar-shared") +
-			simpleModuleDoNotConvertBp2build("cc_library", "baz-shared"),
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "bar-static") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "baz-static") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "bar-shared") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "baz-shared"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("aidl_library", "foo_aidl_library", AttrNameToString{
 				"srcs": `["Foo.aidl"]`,
@@ -4194,11 +4002,25 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_bp2build_cc_library_static", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
+				"copts": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"],
+        "//conditions:default": [],
+    })`,
+				"additional_compiler_inputs": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"],
+        "//conditions:default": [],
+    })`,
 				"local_includes": `["."]`,
 			}),
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
+				"copts": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"],
+        "//conditions:default": [],
+    })`,
+				"additional_compiler_inputs": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"],
+        "//conditions:default": [],
+    })`,
 				"local_includes": `["."]`,
 			}),
 		},
@@ -4631,7 +4453,7 @@
         "-Wextra",
         "-DDEBUG_ONLY_CODE=0",
     ] + select({
-        "//build/bazel/product_variables:eng": [
+        "//build/bazel/product_config/config_settings:eng": [
             "-UDEBUG_ONLY_CODE",
             "-DDEBUG_ONLY_CODE=1",
         ],
@@ -4903,3 +4725,408 @@
 		},
 	})
 }
+
+// Bazel enforces that proto_library and the .proto file are in the same bazel package
+func TestGenerateProtoLibraryInSamePackage(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library depends on .proto files from multiple packages",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	   "bar/bar.proto", // Different package because there is a bar/Android.bp
+	   "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
+	],
+	proto: {
+		canonical_path_from_root: true,
+	}
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp":        "",
+			"baz/subbaz/Android.bp": "",
+		},
+	}
+
+	// We will run the test 3 times and check in the root, bar and baz/subbaz directories
+	// Root dir
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+			"tags": `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[
+        ":foo_proto",
+        "//bar:foo_proto",
+        "//baz/subbaz:foo_proto",
+    ]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// bar dir
+	tc.Dir = "bar"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["//bar:bar.proto"]`,
+			"tags": `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// baz/subbaz dir
+	tc.Dir = "baz/subbaz"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["//baz/subbaz:baz.proto"]`,
+			"tags": `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+// Bazel enforces that proto_library and the .proto file are in the same bazel package
+func TestGenerateProtoLibraryInSamePackageNotCanonicalFromRoot(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library depends on .proto files from multiple packages",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	   "bar/bar.proto", // Different package because there is a bar/Android.bp
+	   "baz/subbaz/baz.proto", // Different package because there is baz/subbaz/Android.bp
+	],
+	proto: {
+		canonical_path_from_root: false,
+	}
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp":        "",
+			"baz/subbaz/Android.bp": "",
+		},
+	}
+
+	// We will run the test 3 times and check in the root, bar and baz/subbaz directories
+	// Root dir
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs":                `["foo.proto"]`,
+			"strip_import_prefix": `""`,
+			"tags":                `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[
+        ":foo_proto",
+        "//bar:foo_proto",
+        "//baz/subbaz:foo_proto",
+    ]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// bar dir
+	tc.Dir = "bar"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs":                `["//bar:bar.proto"]`,
+			"strip_import_prefix": `""`,
+			"import_prefix":       `"bar"`,
+			"tags":                `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// baz/subbaz dir
+	tc.Dir = "baz/subbaz"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs":                `["//baz/subbaz:baz.proto"]`,
+			"strip_import_prefix": `""`,
+			"import_prefix":       `"baz/subbaz"`,
+			"tags":                `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+func TestProtoIncludeDirs(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library depends on .proto files using proto.include_dirs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	],
+	proto: {
+		include_dirs: ["bar"],
+	}
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp":     "",
+			"bar/bar.proto":      "",
+			"bar/baz/Android.bp": "",
+			"bar/baz/baz.proto":  "",
+		},
+	}
+
+	// We will run the test 3 times and check in the root, bar and bar/baz directories
+	// Root dir
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+			"tags": `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[":foo_proto"]`,
+			"transitive_deps": `[
+        "//bar:bar.include_dir_bp2build_generated_proto",
+        "//bar/baz:bar.include_dir_bp2build_generated_proto",
+    ]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// bar dir
+	tc.Dir = "bar"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+			"srcs":                `["bar.proto"]`,
+			"strip_import_prefix": `""`,
+			"tags":                `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// bar/baz dir
+	tc.Dir = "bar/baz"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+			"srcs":                `["//bar/baz:baz.proto"]`,
+			"strip_import_prefix": `""`,
+			"import_prefix":       `"baz"`,
+			"tags":                `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+func TestProtoIncludeDirsWithSrcsInMultiplePackages(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library has srcs in multiple bazel packages and uses proto.include_dirs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	   "bar/bar.proto",
+	],
+	proto: {
+		include_dirs: ["baz"],
+	}
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp": "", // package boundary
+			"baz/Android.bp": "",
+			"baz/baz.proto":  "",
+		},
+	}
+
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+			"tags": `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[
+        ":foo_proto",
+        "//bar:foo_proto",
+    ]`,
+			"transitive_deps": `["//baz:baz.include_dir_bp2build_generated_proto"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+}
+
+func TestProtoLocalIncludeDirs(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library depends on .proto files using proto.local_include_dirs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint:                  SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"foo/Android.bp": `cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	],
+	proto: {
+		local_include_dirs: ["foo_subdir"],
+	},
+	bazel_module: { bp2build_available: true },
+}`,
+			"foo/foo.proto":                   "",
+			"foo/foo_subdir/Android.bp":       "",
+			"foo/foo_subdir/foo_subdir.proto": "",
+		},
+	}
+
+	// We will run the test 2 times and check in foo and foo/foo_subdir directories
+	// foo dir
+	tc.Dir = "foo"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `["//:libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+			"tags": `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps":            `[":foo_proto"]`,
+			"transitive_deps": `["//foo/foo_subdir:foo.foo_subdir.include_dir_bp2build_generated_proto"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+	// foo/foo_subdir
+	tc.Dir = "foo/foo_subdir"
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTargetNoRestrictions("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{
+			"srcs":                `["foo_subdir.proto"]`,
+			"strip_import_prefix": `""`,
+			"tags":                `["manual"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+// `foo_device` and `bar_host` can depend on .proto files of a specific dir,
+// the dynamically generated proto_library should not have any target_compatible_with
+func TestProtoLibraryForIncludeDirsIsOsAgnostic(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "proto_library generated for proto.include_dirs is compatible for all axes",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite") + `
+cc_library {
+	name: "foo_device",
+	device_supported: true, // this is the default behavior, but added explicitly here for illustration
+	host_supported: false,
+	proto: {include_dirs: ["dir"]},
+}
+cc_library {
+	name: "bar_host",
+	device_supported: false,
+	host_supported: true,
+	srcs: ["bar.proto"],
+	proto: {include_dirs: ["dir"]},
+}
+`,
+		Filesystem: map[string]string{
+			"dir/Android.bp": "",
+			"dir/dir.proto":  "",
+		},
+		Dir: "dir", // check for the generated proto_library
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("proto_library", "dir.include_dir_bp2build_generated_proto", AttrNameToString{
+				"srcs":                `["dir.proto"]`,
+				"strip_import_prefix": `""`,
+				"tags":                `["manual"]`,
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
+
+func TestCcCompileMultilibConversion(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library with compile_multilib",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library {
+	name: "lib32",
+	compile_multilib: "32",
+}
+cc_library {
+	name: "lib64",
+	compile_multilib: "64",
+}
+`,
+		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"],
+        "//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"],
+        "//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"],
+        "//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"],
+        "//conditions:default": [],
+    })`,
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 072f5b3..40e8451 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -123,69 +123,6 @@
 	})
 }
 
-func TestCcApiHeaders(t *testing.T) {
-	fs := map[string]string{
-		"bar/Android.bp": `cc_library_headers { name: "bar_headers", }`,
-	}
-	bp := `
-	cc_library_headers {
-		name: "foo_headers",
-		export_include_dirs: ["dir1", "dir2"],
-		export_header_lib_headers: ["bar_headers"],
-
-		arch: {
-			arm: {
-				export_include_dirs: ["dir_arm"],
-			},
-			x86: {
-				export_include_dirs: ["dir_x86"],
-			},
-		},
-
-		target: {
-			android: {
-				export_include_dirs: ["dir1", "dir_android"],
-			},
-			windows: {
-				export_include_dirs: ["dir_windows"],
-			},
-		}
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.arm", AttrNameToString{
-			"export_includes": `["dir_arm"]`,
-			"arch":            `"arm"`,
-		}),
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.x86", AttrNameToString{
-			"export_includes": `["dir_x86"]`,
-			"arch":            `"x86"`,
-		}),
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution.androidos", AttrNameToString{
-			"export_includes": `["dir_android"]`, // common includes are deduped
-		}),
-		// Windows headers are not exported
-		MakeBazelTarget("cc_api_library_headers", "foo_headers.contribution", AttrNameToString{
-			"export_includes": `[
-        "dir1",
-        "dir2",
-    ]`,
-			"deps": `[
-        "//bar:bar_headers.contribution",
-        ":foo_headers.contribution.arm",
-        ":foo_headers.contribution.x86",
-        ":foo_headers.contribution.androidos",
-    ]`,
-		}),
-	}
-	RunApiBp2BuildTestCase(t, cc.RegisterLibraryHeadersBuildComponents, Bp2buildTestCase{
-		Blueprint:            bp,
-		Description:          "Header library contributions to API surfaces",
-		ExpectedBazelTargets: expectedBazelTargets,
-		Filesystem:           fs,
-	})
-}
-
 // header_libs has "variant_prepend" tag. In bp2build output,
 // variant info(select) should go before general info.
 func TestCcLibraryHeadersOsSpecificHeader(t *testing.T) {
@@ -403,7 +340,7 @@
 		static_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -425,7 +362,7 @@
 		shared_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -447,7 +384,7 @@
 		header_libs: ["foo_export", "foo_no_reexport"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
@@ -468,7 +405,7 @@
 		whole_static_libs: ["foo_export"],
     bazel_module: { bp2build_available: true },
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_headers", "foo_export"),
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_headers", "foo_headers", AttrNameToString{
 				"deps": `[":foo_export"]`,
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index ccb426f..44b9722 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -661,7 +661,7 @@
             ":libapexfoo_stable",
         ],
         "//build/bazel/rules/apex:system": [
-            "@api_surfaces//module-libapi/current:libplatform_stable",
+            ":libplatform_stable",
             "@api_surfaces//module-libapi/current:libapexfoo_stable",
         ],
         "//conditions:default": [
@@ -1225,7 +1225,14 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_shared", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
+				"copts": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"],
+        "//conditions:default": [],
+    })`,
+				"additional_compiler_inputs": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"],
+        "//conditions:default": [],
+    })`,
 				"local_includes": `["."]`,
 			}),
 		},
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 8084a5d..b9508e9 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1003,6 +1003,38 @@
 	})
 }
 
+func TestCcLibraryStaticGeneratedHeadersMultipleExports(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Blueprint: soongCcLibraryStaticPreamble + `
+genrule {
+    name: "generated_hdr",
+    cmd: "nothing to see here",
+    export_include_dirs: ["foo", "bar"],
+    bazel_module: { bp2build_available: false },
+}
+
+genrule {
+    name: "export_generated_hdr",
+    cmd: "nothing to see here",
+    export_include_dirs: ["a", "b"],
+    bazel_module: { bp2build_available: false },
+}
+
+cc_library_static {
+    name: "foo_static",
+    generated_headers: ["generated_hdr", "export_generated_hdr"],
+    export_generated_headers: ["export_generated_hdr"],
+    include_build_directory: false,
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
+				"deps":                `[":export_generated_hdr__header_library"]`,
+				"implementation_deps": `[":generated_hdr__header_library"]`,
+			}),
+		},
+	})
+}
+
 // generated_headers has "variant_prepend" tag. In bp2build output,
 // variant info(select) should go before general info.
 func TestCcLibraryStaticArchSrcsExcludeSrcsGeneratedFiles(t *testing.T) {
@@ -1013,17 +1045,17 @@
 			"for-x86.cpp":            "",
 			"not-for-x86.cpp":        "",
 			"not-for-everything.cpp": "",
-			"dep/Android.bp": simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
-				simpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
+			"dep/Android.bp": SimpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg") +
+				SimpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg") +
+				SimpleModuleDoNotConvertBp2build("genrule", "generated_src_other_pkg_x86") +
+				SimpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_x86") +
+				SimpleModuleDoNotConvertBp2build("genrule", "generated_hdr_other_pkg_android"),
 		},
 		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
-			simpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + `
+			SimpleModuleDoNotConvertBp2build("genrule", "generated_src") +
+			SimpleModuleDoNotConvertBp2build("genrule", "generated_src_not_x86") +
+			SimpleModuleDoNotConvertBp2build("genrule", "generated_src_android") +
+			SimpleModuleDoNotConvertBp2build("genrule", "generated_hdr") + `
 cc_library_static {
     name: "foo_static",
     srcs: ["common.cpp", "not-for-*.cpp"],
@@ -1156,13 +1188,13 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"copts": `select({
-        "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
+        "//build/bazel/product_config/config_settings:binder32bit": ["-Wbinder32bit"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
+        "//build/bazel/product_config/config_settings:malloc_zero_contents": ["-Wmalloc_zero_contents"],
         "//conditions:default": [],
     })`,
 				"srcs_c": `["common.c"]`,
@@ -1216,19 +1248,19 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"copts": `select({
-        "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
+        "//build/bazel/product_config/config_settings:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
         "//conditions:default": [],
     })`,
 				"srcs_c": `["common.c"]`,
@@ -1255,7 +1287,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
 				"asflags": `select({
-        "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+        "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
         "//conditions:default": [],
     })`,
 				"srcs_as": `["common.S"]`,
@@ -1428,7 +1460,7 @@
 	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_static system_shared_libs set for bionic variant",
 		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+			SimpleModuleDoNotConvertBp2build("cc_library", "libc") + `
 cc_library {
 	name: "libc_musl",
 	bazel_module: { bp2build_available: false },
@@ -1461,8 +1493,8 @@
 	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_static system_shared_libs set for root and linux_bionic variant",
 		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") +
-			simpleModuleDoNotConvertBp2build("cc_library", "libm") + `
+			SimpleModuleDoNotConvertBp2build("cc_library", "libc") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "libm") + `
 cc_library {
 	name: "libc_musl",
 	bazel_module: { bp2build_available: false },
@@ -1495,7 +1527,7 @@
 	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
 		Description: "cc_library_static system_shared_lib empty for linux_bionic variant",
 		Blueprint: soongCcLibraryStaticPreamble +
-			simpleModuleDoNotConvertBp2build("cc_library", "libc") + `
+			SimpleModuleDoNotConvertBp2build("cc_library", "libc") + `
 
 cc_library {
     name: "libm",
@@ -1918,7 +1950,14 @@
 `,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
-				"features":       `["sanitizer_blocklist_foo_blocklist_txt"]`,
+				"copts": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": ["-fsanitize-ignorelist=$(location foo_blocklist.txt)"],
+        "//conditions:default": [],
+    })`,
+				"additional_compiler_inputs": `select({
+        "//build/bazel/rules/cc:sanitizers_enabled": [":foo_blocklist.txt"],
+        "//conditions:default": [],
+    })`,
 				"local_includes": `["."]`,
 			}),
 		},
@@ -2215,3 +2254,38 @@
     ]`,
 			})}})
 }
+
+func TestCcLibraryWithProtoInGeneratedSrcs(t *testing.T) {
+	runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+		Description:                "cc_library with a .proto file generated from a genrule",
+		ModuleTypeUnderTest:        "cc_library_static",
+		ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+		Blueprint: soongCcLibraryPreamble + `
+cc_library_static {
+	name: "mylib",
+	generated_sources: ["myprotogen"],
+}
+genrule {
+	name: "myprotogen",
+	out: ["myproto.proto"],
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_library_static", "mylib", AttrNameToString{
+				"local_includes":                    `["."]`,
+				"deps":                              `[":libprotobuf-cpp-lite"]`,
+				"implementation_whole_archive_deps": `[":mylib_cc_proto_lite"]`,
+			}),
+			MakeBazelTarget("cc_lite_proto_library", "mylib_cc_proto_lite", AttrNameToString{
+				"deps": `[":mylib_proto"]`,
+			}),
+			MakeBazelTarget("proto_library", "mylib_proto", AttrNameToString{
+				"srcs": `[":myprotogen"]`,
+			}),
+			MakeBazelTargetNoRestrictions("genrule", "myprotogen", AttrNameToString{
+				"cmd":  `""`,
+				"outs": `["myproto.proto"]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index eab84e1..ecfcb5a 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -200,7 +200,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("cc_object", "foo", AttrNameToString{
 				"asflags": `select({
-        "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+        "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
         "//conditions:default": [],
     })`,
 				"copts":               `["-fno-addrsig"]`,
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 684fd03..74a5c0d 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -89,14 +89,14 @@
     host_supported: true,
     include_build_directory: false,
 }
-` + simpleModuleDoNotConvertBp2build("cc_library", "foolib") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
-			simpleModuleDoNotConvertBp2build("genrule", "data_mod") +
-			simpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
-			simpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
-			simpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library", "foolib") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "hostlib") +
+			SimpleModuleDoNotConvertBp2build("genrule", "data_mod") +
+			SimpleModuleDoNotConvertBp2build("cc_binary", "cc_bin") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "cc_lib") +
+			SimpleModuleDoNotConvertBp2build("cc_test_library", "cc_test_lib2") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
 		targets: []testBazelTarget{
 			{"cc_library_shared", "cc_test_lib1", AttrNameToString{}},
 			{"cc_library_static", "cc_test_lib1_bp2build_cc_library_static", AttrNameToString{}},
@@ -120,8 +120,6 @@
         "//build/bazel/platforms/os:windows": [":hostlib"],
         "//conditions:default": [],
     })`,
-				"gtest":          "True",
-				"isolated":       "True",
 				"local_includes": `["."]`,
 				"dynamic_deps": `[":cc_test_lib2"] + select({
         "//build/bazel/platforms/os:android": [":foolib"],
@@ -137,6 +135,17 @@
         "//build/bazel/platforms/os:linux_musl": ["linux.cpp"],
         "//conditions:default": [],
     })`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -158,9 +167,19 @@
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
 				"gtest":          "False",
-				"isolated":       "False",
 				"local_includes": `["."]`,
 				"srcs":           `["test.cpp"]`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -177,19 +196,28 @@
     srcs: ["test.cpp"],
     test_options: { tags: ["no-remote"] },
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
 				"tags":           `["no-remote"]`,
 				"local_includes": `["."]`,
 				"srcs":           `["test.cpp"]`,
-				"gtest":          "True",
-				"isolated":       "True",
 				"deps": `[
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `[
+        "host_without_device",
+        "device",
+    ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -208,12 +236,10 @@
 	srcs: ["test.cpp"],
 	test_config: "test_config.xml",
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
-				"gtest":                  "True",
-				"isolated":               "True",
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
@@ -222,6 +248,14 @@
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -232,27 +266,35 @@
 	runCcTestTestCase(t, ccTestBp2buildTestCase{
 		description: "cc test that defaults to test config AndroidTest.xml",
 		filesystem: map[string]string{
-			"AndroidTest.xml": "",
+			"AndroidTest.xml":   "",
+			"DynamicConfig.xml": "",
 		},
 		blueprint: `
 cc_test {
 	name: "mytest",
 	srcs: ["test.cpp"],
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
-				"gtest":                  "True",
-				"isolated":               "True",
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
 				"test_config":            `"AndroidTest.xml"`,
+				"dynamic_config":         `"DynamicConfig.xml"`,
 				"deps": `[
         ":libgtest_main",
         ":libgtest",
     ]`,
+				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -271,14 +313,13 @@
 	srcs: ["test.cpp"],
 	test_config_template: "test_config_template.xml",
 	auto_gen_config: true,
+	isolated: true,
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
 				"auto_generate_test_config": "True",
-				"gtest":                     "True",
-				"isolated":                  "True",
 				"local_includes":            `["."]`,
 				"srcs":                      `["test.cpp"]`,
 				"target_compatible_with":    `["//build/bazel/platforms/os:android"]`,
@@ -288,10 +329,16 @@
     ]`,
 				"template_install_base": `"/data/local/tmp"`,
 				"template_test_config":  `"test_config_template.xml"`,
-				"deps": `[
-        ":libgtest_main",
-        ":libgtest",
-    ]`,
+				"deps":                  `[":libgtest_isolated_main"]`,
+				"dynamic_deps":          `[":liblog"]`,
+				"runs_on":               `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -307,12 +354,10 @@
 	srcs: ["test.cpp"],
 	static_libs: ["libgtest"],
 }
-` + simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
-			simpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
 		targets: []testBazelTarget{
 			{"cc_test", "mytest", AttrNameToString{
-				"gtest":                  "True",
-				"isolated":               "True",
 				"local_includes":         `["."]`,
 				"srcs":                   `["test.cpp"]`,
 				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
@@ -320,9 +365,254 @@
         ":libgtest",
         ":libgtest_main",
     ]`,
+				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
 	})
 
 }
+
+func TestCcTest_WithIsolatedTurnedOn(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test that sets `isolated: true` should run with ligtest_isolated_main instead of libgtest_main",
+		blueprint: `
+cc_test {
+	name: "mytest",
+	srcs: ["test.cpp"],
+	isolated: true,
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["test.cpp"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"deps":                   `[":libgtest_isolated_main"]`,
+				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+
+}
+
+func TestCcTest_GtestExplicitlySpecifiedInAndroidBp(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "If `gtest` is explicit in Android.bp, it should be explicit in BUILD files as well",
+		blueprint: `
+cc_test {
+	name: "mytest_with_gtest",
+	gtest: true,
+}
+cc_test {
+	name: "mytest_with_no_gtest",
+	gtest: false,
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest_with_gtest", AttrNameToString{
+				"local_includes": `["."]`,
+				"deps": `[
+        ":libgtest_main",
+        ":libgtest",
+    ]`,
+				"gtest":                  "True",
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+			{"cc_test", "mytest_with_no_gtest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"gtest":                  "False",
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+}
+
+func TestCcTest_DisableMemtagHeap(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test that disable memtag_heap",
+		blueprint: `
+cc_test {
+	name: "mytest",
+	srcs: ["test.cpp"],
+	isolated: true,
+	sanitize: {
+		cfi: true,
+		memtag_heap: false,
+	},
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["test.cpp"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"deps":                   `[":libgtest_isolated_main"]`,
+				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
+				"features": `["android_cfi"] + select({
+        "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+}
+
+func TestCcTest_RespectArm64MemtagHeap(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test that disable memtag_heap",
+		blueprint: `
+cc_test {
+	name: "mytest",
+	srcs: ["test.cpp"],
+	isolated: true,
+	target: {
+		android_arm64: {
+			sanitize: {
+				memtag_heap: false,
+			}
+		}
+	},
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["test.cpp"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"deps":                   `[":libgtest_isolated_main"]`,
+				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": ["-memtag_heap"],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+}
+
+func TestCcTest_IgnoreNoneArm64MemtagHeap(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test that disable memtag_heap",
+		blueprint: `
+cc_test {
+	name: "mytest",
+	srcs: ["test.cpp"],
+	isolated: true,
+	arch: {
+		x86: {
+			sanitize: {
+				memtag_heap: false,
+			}
+		}
+	},
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["test.cpp"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"deps":                   `[":libgtest_isolated_main"]`,
+				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+}
+
+func TestCcTest_Arm64MemtagHeapOverrideNoConfigOne(t *testing.T) {
+	runCcTestTestCase(t, ccTestBp2buildTestCase{
+		description: "cc test that disable memtag_heap",
+		blueprint: `
+cc_test {
+	name: "mytest",
+	srcs: ["test.cpp"],
+	isolated: true,
+	sanitize: {
+		memtag_heap: true,
+	},
+	target: {
+		android_arm64: {
+			sanitize: {
+				memtag_heap: false,
+				diag: {
+					memtag_heap: false,
+				},
+			}
+		}
+	},
+}
+` + SimpleModuleDoNotConvertBp2build("cc_library_static", "libgtest_isolated_main") +
+			SimpleModuleDoNotConvertBp2build("cc_library", "liblog"),
+		targets: []testBazelTarget{
+			{"cc_test", "mytest", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["test.cpp"]`,
+				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+				"deps":                   `[":libgtest_isolated_main"]`,
+				"dynamic_deps":           `[":liblog"]`,
+				"runs_on":                `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "-memtag_heap",
+            "-diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
+			},
+			},
+		},
+	})
+}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index d5f2386..da4b5cf 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,7 +1,6 @@
 package bp2build
 
 import (
-	"android/soong/starlark_fmt"
 	"encoding/json"
 	"fmt"
 	"reflect"
@@ -9,11 +8,12 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/apex"
 	"android/soong/cc"
 	cc_config "android/soong/cc/config"
 	java_config "android/soong/java/config"
-
-	"android/soong/apex"
+	rust_config "android/soong/rust/config"
+	"android/soong/starlark_fmt"
 
 	"github.com/google/blueprint/proptools"
 )
@@ -38,6 +38,9 @@
 	files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
 	files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
 
+	files = append(files, newFile("rust_toolchain", GeneratedBuildFileName, "")) // Creates a //rust_toolchain package.
+	files = append(files, newFile("rust_toolchain", "constants.bzl", rust_config.BazelRustToolchainVars(cfg)))
+
 	files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
 	apexToolchainVars, err := apex.BazelApexToolchainVars()
 	if err != nil {
@@ -45,7 +48,11 @@
 	}
 	files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars))
 
-	files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.Serialize().ConvertedModules, "\n")))
+	if buf, err := json.MarshalIndent(metrics.convertedModuleWithType, "", "  "); err != nil {
+		return []BazelFile{}, err
+	} else {
+		files = append(files, newFile("metrics", "converted_modules.json", string(buf)))
+	}
 
 	convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
 	if err != nil {
@@ -105,12 +112,7 @@
 `, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
 }
 
-func CreateBazelFiles(
-	cfg android.Config,
-	ruleShims map[string]RuleShim,
-	buildToTargets map[string]BazelTargets,
-	mode CodegenMode) []BazelFile {
-
+func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	var files []BazelFile
 
 	if mode == QueryView {
@@ -143,7 +145,7 @@
 		targets.sort()
 
 		var content string
-		if mode == Bp2Build || mode == ApiBp2build {
+		if mode == Bp2Build {
 			content = `# READ THIS FIRST:
 # This file was automatically generated by bp2build for the Bazel migration project.
 # Feel free to edit or test it, but do *not* check it into your version control system.
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 00ffd79..89dd38e 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -27,8 +27,7 @@
 }
 
 func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
-	files := CreateBazelFiles(android.NullConfig("out", "out/soong"),
-		map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
+	files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
 	expectedFilePaths := []bazelFilepath{
 		{
 			dir:      "",
@@ -118,6 +117,14 @@
 			basename: "constants.bzl",
 		},
 		{
+			dir:      "rust_toolchain",
+			basename: GeneratedBuildFileName,
+		},
+		{
+			dir:      "rust_toolchain",
+			basename: "constants.bzl",
+		},
+		{
 			dir:      "apex_toolchain",
 			basename: GeneratedBuildFileName,
 		},
@@ -127,7 +134,7 @@
 		},
 		{
 			dir:      "metrics",
-			basename: "converted_modules.txt",
+			basename: "converted_modules.json",
 		},
 		{
 			dir:      "metrics",
diff --git a/bp2build/droidstubs_conversion_test.go b/bp2build/droidstubs_conversion_test.go
deleted file mode 100644
index 12c1cfe..0000000
--- a/bp2build/droidstubs_conversion_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright 2022 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bp2build
-
-import (
-	"testing"
-
-	"android/soong/android"
-	"android/soong/java"
-)
-
-func registerJavaApiModules(ctx android.RegistrationContext) {
-	java.RegisterSdkLibraryBuildComponents(ctx)
-	java.RegisterStubsBuildComponents(ctx)
-}
-
-func TestDroidstubsApiContributions(t *testing.T) {
-	bp := `
-	droidstubs {
-		name: "framework-stubs",
-		check_api: {
-			current: {
-				api_file: "framework.current.txt",
-			},
-		},
-	}
-
-	// Modules without check_api should not generate a Bazel API target
-	droidstubs {
-		name: "framework-docs",
-	}
-
-	// java_sdk_library is a macro that creates droidstubs
-	java_sdk_library {
-		name: "module-stubs",
-		srcs: ["A.java"],
-
-		// These api surfaces are added by default, but add them explicitly to make
-		// this test hermetic
-		public: {
-			enabled: true,
-		},
-		system: {
-			enabled: true,
-		},
-
-		// Disable other api surfaces to keep unit test scope limited
-		module_lib: {
-			enabled: false,
-		},
-		test: {
-			enabled: false,
-		},
-	}
-	`
-	expectedBazelTargets := []string{
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"framework-stubs.contribution",
-			AttrNameToString{
-				"api":                    `"framework.current.txt"`,
-				"api_surface":            `"publicapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"module-stubs.stubs.source.contribution",
-			AttrNameToString{
-				"api":                    `"api/current.txt"`,
-				"api_surface":            `"publicapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-		MakeBazelTargetNoRestrictions(
-			"java_api_contribution",
-			"module-stubs.stubs.source.system.contribution",
-			AttrNameToString{
-				"api":                    `"api/system-current.txt"`,
-				"api_surface":            `"systemapi"`,
-				"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
-			}),
-	}
-	RunApiBp2BuildTestCase(t, registerJavaApiModules, Bp2buildTestCase{
-		Blueprint:            bp,
-		ExpectedBazelTargets: expectedBazelTargets,
-		Filesystem: map[string]string{
-			"api/current.txt":        "",
-			"api/removed.txt":        "",
-			"api/system-current.txt": "",
-			"api/system-removed.txt": "",
-		},
-	})
-}
diff --git a/bp2build/filegroup_conversion_test.go b/bp2build/filegroup_conversion_test.go
index 7ce559d..cb2e207 100644
--- a/bp2build/filegroup_conversion_test.go
+++ b/bp2build/filegroup_conversion_test.go
@@ -137,7 +137,7 @@
 		path: "proto",
 }`,
 		ExpectedBazelTargets: []string{
-			MakeBazelTargetNoRestrictions("proto_library", "foo_bp2build_converted", AttrNameToString{
+			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
 				"srcs":                `["proto/foo.proto"]`,
 				"strip_import_prefix": `"proto"`,
 				"tags": `[
@@ -145,6 +145,13 @@
         "manual",
     ]`,
 			}),
+			MakeBazelTargetNoRestrictions("alias", "foo_bp2build_converted", AttrNameToString{
+				"actual": `"//.:foo_proto"`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`,
+			}),
 			MakeBazelTargetNoRestrictions("filegroup", "foo", AttrNameToString{
 				"srcs": `["proto/foo.proto"]`}),
 		}})
@@ -170,3 +177,27 @@
     ]`}),
 		}})
 }
+
+func TestFilegroupWithProtoInDifferentPackage(t *testing.T) {
+	runFilegroupTestCase(t, Bp2buildTestCase{
+		Description: "filegroup with .proto in different package",
+		Filesystem: map[string]string{
+			"subdir/Android.bp": "",
+		},
+		Blueprint: `
+filegroup {
+    name: "foo",
+    srcs: ["subdir/foo.proto"],
+}`,
+		Dir: "subdir", // check in subdir
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("proto_library", "foo_proto", AttrNameToString{
+				"srcs":                `["//subdir:foo.proto"]`,
+				"import_prefix":       `"subdir"`,
+				"strip_import_prefix": `""`,
+				"tags": `[
+        "apex_available=//apex_available:anyapex",
+        "manual",
+    ]`}),
+		}})
+}
diff --git a/bp2build/genrule_conversion_test.go b/bp2build/genrule_conversion_test.go
index 5cf4fb2..2a10a14 100644
--- a/bp2build/genrule_conversion_test.go
+++ b/bp2build/genrule_conversion_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"testing"
 
 	"android/soong/android"
@@ -26,6 +27,8 @@
 
 func registerGenruleModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("genrule_defaults", func() android.Module { return genrule.DefaultsFactory() })
+	ctx.RegisterModuleType("cc_binary", func() android.Module { return cc.BinaryFactory() })
+	ctx.RegisterModuleType("soong_namespace", func() android.Module { return android.NamespaceFactory() })
 }
 
 func runGenruleTestCase(t *testing.T, tc Bp2buildTestCase) {
@@ -695,3 +698,257 @@
 			})
 	})
 }
+
+func TestGenruleWithExportIncludeDirs(t *testing.T) {
+	testCases := []struct {
+		moduleType string
+		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
+	}{
+		{
+			moduleType: "genrule",
+			factory:    genrule.GenRuleFactory,
+		},
+		{
+			moduleType: "cc_genrule",
+			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule",
+			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule_host",
+			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
+		},
+	}
+
+	dir := "baz"
+
+	bp := `%s {
+    name: "foo",
+    out: ["foo.out.h"],
+    srcs: ["foo.in"],
+    cmd: "cp $(in) $(out)",
+    export_include_dirs: ["foo", "bar", "."],
+    bazel_module: { bp2build_available: true },
+}`
+
+	for _, tc := range testCases {
+		moduleAttrs := AttrNameToString{
+			"cmd":  `"cp $(SRCS) $(OUTS)"`,
+			"outs": `["foo.out.h"]`,
+			"srcs": `["foo.in"]`,
+		}
+
+		expectedBazelTargets := []string{
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
+			makeBazelTargetHostOrDevice("cc_library_headers", "foo__header_library", AttrNameToString{
+				"hdrs": `[":foo"]`,
+				"export_includes": `[
+        "foo",
+        "baz/foo",
+        "bar",
+        "baz/bar",
+        ".",
+        "baz",
+    ]`,
+			},
+				tc.hod),
+		}
+
+		t.Run(tc.moduleType, func(t *testing.T) {
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {},
+				Bp2buildTestCase{
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					Filesystem: map[string]string{
+						filepath.Join(dir, "Android.bp"): fmt.Sprintf(bp, tc.moduleType),
+					},
+					Dir:                  dir,
+					ExpectedBazelTargets: expectedBazelTargets,
+				})
+		})
+	}
+}
+
+func TestGenruleWithSoongConfigVariableConfiguredCmd(t *testing.T) {
+	testCases := []struct {
+		moduleType string
+		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
+	}{
+		{
+			moduleType: "genrule",
+			factory:    genrule.GenRuleFactory,
+		},
+		{
+			moduleType: "cc_genrule",
+			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule",
+			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule_host",
+			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
+		},
+	}
+
+	bp := `
+soong_config_module_type {
+    name: "my_genrule",
+    module_type: "%s",
+    config_namespace: "my_namespace",
+    bool_variables: ["my_variable"],
+    properties: ["cmd"],
+}
+
+my_genrule {
+    name: "foo",
+    out: ["foo.txt"],
+    cmd: "echo 'no variable' > $(out)",
+    soong_config_variables: {
+        my_variable: {
+            cmd: "echo 'with variable' > $(out)",
+        },
+    },
+    bazel_module: { bp2build_available: true },
+}
+`
+
+	for _, tc := range testCases {
+		moduleAttrs := AttrNameToString{
+			"cmd": `select({
+        "//build/bazel/product_config/config_settings:my_namespace__my_variable": "echo 'with variable' > $(OUTS)",
+        "//conditions:default": "echo 'no variable' > $(OUTS)",
+    })`,
+			"outs": `["foo.txt"]`,
+		}
+
+		expectedBazelTargets := []string{
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
+		}
+
+		t.Run(tc.moduleType, func(t *testing.T) {
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { android.RegisterSoongConfigModuleBuildComponents(ctx) },
+				Bp2buildTestCase{
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					ExpectedBazelTargets:       expectedBazelTargets,
+				})
+		})
+	}
+}
+
+func TestGenruleWithProductVariableConfiguredCmd(t *testing.T) {
+	testCases := []struct {
+		moduleType string
+		factory    android.ModuleFactory
+		hod        android.HostOrDeviceSupported
+	}{
+		{
+			moduleType: "genrule",
+			factory:    genrule.GenRuleFactory,
+		},
+		{
+			moduleType: "cc_genrule",
+			factory:    cc.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule",
+			factory:    java.GenRuleFactory,
+			hod:        android.DeviceSupported,
+		},
+		{
+			moduleType: "java_genrule_host",
+			factory:    java.GenRuleFactoryHost,
+			hod:        android.HostSupported,
+		},
+	}
+
+	bp := `
+
+%s {
+    name: "foo",
+    out: ["foo.txt"],
+    cmd: "echo 'no variable' > $(out)",
+    product_variables: {
+        debuggable: {
+            cmd: "echo 'with variable' > $(out)",
+        },
+    },
+    bazel_module: { bp2build_available: true },
+}
+`
+
+	for _, tc := range testCases {
+		moduleAttrs := AttrNameToString{
+			"cmd": `select({
+        "//build/bazel/product_config/config_settings:debuggable": "echo 'with variable' > $(OUTS)",
+        "//conditions:default": "echo 'no variable' > $(OUTS)",
+    })`,
+			"outs": `["foo.txt"]`,
+		}
+
+		expectedBazelTargets := []string{
+			makeBazelTargetHostOrDevice("genrule", "foo", moduleAttrs, tc.hod),
+		}
+
+		t.Run(tc.moduleType, func(t *testing.T) {
+			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { android.RegisterSoongConfigModuleBuildComponents(ctx) },
+				Bp2buildTestCase{
+					Blueprint:                  fmt.Sprintf(bp, tc.moduleType),
+					ModuleTypeUnderTest:        tc.moduleType,
+					ModuleTypeUnderTestFactory: tc.factory,
+					ExpectedBazelTargets:       expectedBazelTargets,
+				})
+		})
+	}
+}
+
+func TestGenruleWithModulesInNamespaces(t *testing.T) {
+	bp := `
+genrule {
+	name: "mygenrule",
+	cmd: "echo $(location //mynamespace:mymodule) > $(out)",
+	srcs: ["//mynamespace:mymodule"],
+	out: ["myout"],
+}
+`
+	fs := map[string]string{
+		"mynamespace/Android.bp":     `soong_namespace {}`,
+		"mynamespace/dir/Android.bp": `cc_binary {name: "mymodule"}`,
+	}
+	expectedBazelTargets := []string{
+		MakeBazelTargetNoRestrictions("genrule", "mygenrule", AttrNameToString{
+			// The fully qualified soong label is <namespace>:<module_name>
+			// - here the prefix is mynamespace
+			// The fully qualifed bazel label is <package>:<module_name>
+			// - here the prefix is mynamespace/dir, since there is a BUILD file at each level of this FS path
+			"cmd":  `"echo $(location //mynamespace/dir:mymodule) > $(OUTS)"`,
+			"outs": `["myout"]`,
+			"srcs": `["//mynamespace/dir:mymodule"]`,
+		}),
+	}
+
+	t.Run("genrule that uses module from a different namespace", func(t *testing.T) {
+		runGenruleTestCase(t, Bp2buildTestCase{
+			Blueprint:                  bp,
+			Filesystem:                 fs,
+			ModuleTypeUnderTest:        "genrule",
+			ModuleTypeUnderTestFactory: genrule.GenRuleFactory,
+			ExpectedBazelTargets:       expectedBazelTargets,
+		})
+	})
+
+}
diff --git a/bp2build/go_conversion_test.go b/bp2build/go_conversion_test.go
index 507fbf0..2387641 100644
--- a/bp2build/go_conversion_test.go
+++ b/bp2build/go_conversion_test.go
@@ -45,11 +45,17 @@
 		srcs: [
 			"foo_linux.go",
 		],
+		testSrcs: [
+			"foo_linux_test.go",
+		],
 	},
 	darwin: {
 		srcs: [
 			"foo_darwin.go",
 		],
+		testSrcs: [
+			"foo_darwin_test.go",
+		],
 	},
 	testSrcs: [
 		"foo1_test.go",
@@ -84,7 +90,21 @@
     })`,
 			},
 			android.HostSupported,
-		)},
+		),
+			makeBazelTargetHostOrDevice("go_test", "foo-test",
+				AttrNameToString{
+					"embed": `[":foo"]`,
+					"srcs": `[
+        "foo1_test.go",
+        "foo2_test.go",
+    ] + select({
+        "//build/bazel/platforms/os:darwin": ["foo_darwin_test.go"],
+        "//build/bazel/platforms/os:linux_glibc": ["foo_linux_test.go"],
+        "//conditions:default": [],
+    })`,
+				},
+				android.HostSupported,
+			)},
 	})
 }
 
@@ -125,6 +145,44 @@
 	})
 }
 
+func TestConvertGoBinaryWithTestSrcs(t *testing.T) {
+	bp := `
+blueprint_go_binary {
+	name: "foo",
+	srcs: ["main.go"],
+	testSrcs: ["main_test.go"],
+}
+`
+	t.Parallel()
+	runGoTests(t, Bp2buildTestCase{
+		Description: "Convert blueprint_go_binary with testSrcs",
+		Blueprint:   bp,
+		ExpectedBazelTargets: []string{
+			makeBazelTargetHostOrDevice("go_binary", "foo",
+				AttrNameToString{
+					"deps":  `[]`,
+					"embed": `[":foo-source"]`,
+				},
+				android.HostSupported,
+			),
+			makeBazelTargetHostOrDevice("go_source", "foo-source",
+				AttrNameToString{
+					"deps": `[]`,
+					"srcs": `["main.go"]`,
+				},
+				android.HostSupported,
+			),
+			makeBazelTargetHostOrDevice("go_test", "foo-test",
+				AttrNameToString{
+					"embed": `[":foo-source"]`,
+					"srcs":  `["main_test.go"]`,
+				},
+				android.HostSupported,
+			),
+		},
+	})
+}
+
 func TestConvertGoBinaryWithSrcInDifferentPackage(t *testing.T) {
 	bp := `
 blueprint_go_binary {
diff --git a/bp2build/java_host_for_device_conversion_test.go b/bp2build/java_host_for_device_conversion_test.go
index 448cba4..1fa7126 100644
--- a/bp2build/java_host_for_device_conversion_test.go
+++ b/bp2build/java_host_for_device_conversion_test.go
@@ -48,6 +48,7 @@
     name: "java-lib-2",
     srcs: ["b.java"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_host_for_device", "java-lib-1", AttrNameToString{
@@ -57,7 +58,8 @@
 				"sdk_version": `"none"`,
 			}),
 			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
-				"srcs": `["b.java"]`,
+				"srcs":        `["b.java"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
 		},
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index c501a7b..8c78217 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -42,22 +42,26 @@
     srcs: ["a.java", "b.java"],
     exclude_srcs: ["b.java"],
     libs: ["java-lib-2"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }
 
 java_library {
     name: "java-lib-2",
     srcs: ["b.java"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"srcs": `["a.java"]`,
-				"deps": `[":java-lib-2-neverlink"]`,
+				"srcs":        `["a.java"]`,
+				"deps":        `[":java-lib-2-neverlink"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{
-				"srcs": `["b.java"]`,
+				"srcs":        `["b.java"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
 		},
@@ -71,18 +75,21 @@
     srcs: ["a.java"],
     libs: ["java-lib-2"],
     static_libs: ["java-lib-3"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }
 
 java_library {
     name: "java-lib-2",
     srcs: ["b.java"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: false },
 }
 
 java_library {
     name: "java-lib-3",
     srcs: ["c.java"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: false },
 }`,
 		ExpectedBazelTargets: []string{
@@ -92,7 +99,8 @@
         ":java-lib-2-neverlink",
         ":java-lib-3",
     ]`,
-				"exports": `[":java-lib-3"]`,
+				"exports":     `[":java-lib-3"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -104,6 +112,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     static_libs: ["java-lib-2"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }
 
@@ -114,25 +123,40 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"exports": `[":java-lib-2"]`,
+				"exports":     `[":java-lib-2"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
 	})
 }
 
+func TestJavaLibraryFailsToConvertNoSdkVersion(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `
+java_library {
+    name: "lib",
+    bazel_module: { bp2build_available: true },
+}
+`,
+		ExpectedBazelTargets: []string{}, // no targets expected because sdk_version is not set
+	})
+}
+
 func TestJavaLibraryFailsToConvertLibsWithNoSrcs(t *testing.T) {
 	runJavaLibraryTestCase(t, Bp2buildTestCase{
 		ExpectedErr: fmt.Errorf("Module has direct dependencies but no sources. Bazel will not allow this."),
 		Blueprint: `java_library {
     name: "java-lib-1",
     libs: ["java-lib-2"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }
 
 java_library {
     name: "java-lib-2",
     srcs: ["a.java"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: false },
 }`,
 		ExpectedBazelTargets: []string{},
@@ -144,6 +168,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     plugins: ["java-plugin-1"],
+    sdk_version: "current",
     bazel_module: { bp2build_available: true },
 }
 
@@ -154,7 +179,8 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"plugins": `[":java-plugin-1"]`,
+				"plugins":     `[":java-plugin-1"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -169,16 +195,21 @@
     name: "java-lib-1",
     srcs: ["a.java"],
     java_version: "11",
+    sdk_version: "current",
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"srcs":         `["a.java"]`,
 				"java_version": `"11"`,
+				"sdk_version":  `"current"`,
 			}),
 			MakeNeverlinkDuplicateTargetWithAttrs(
 				"java_library",
 				"java-lib-1",
-				AttrNameToString{"java_version": `"11"`}),
+				AttrNameToString{
+					"java_version": `"11"`,
+					"sdk_version":  `"current"`,
+				}),
 		},
 	})
 }
@@ -189,6 +220,7 @@
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
+    sdk_version: "current",
     errorprone: {
         enabled: true,
         javacflags: ["-Xep:SpeedLimit:OFF"],
@@ -209,6 +241,7 @@
 				"plugins":                 `[":plugin2"]`,
 				"srcs":                    `["a.java"]`,
 				"errorprone_force_enable": `True`,
+				"sdk_version":             `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -222,6 +255,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
+    sdk_version: "current",
     javacflags: ["-Xsuper-fast"],
     errorprone: {
         javacflags: ["-Xep:SpeedLimit:OFF"],
@@ -229,8 +263,9 @@
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
-				"javacopts": `["-Xsuper-fast"]`,
-				"srcs":      `["a.java"]`,
+				"javacopts":   `["-Xsuper-fast"]`,
+				"srcs":        `["a.java"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -243,6 +278,7 @@
     name: "java-lib-1",
     srcs: ["a.java"],
     javacflags: ["-Xsuper-fast"],
+    sdk_version: "current",
     errorprone: {
     enabled: false,
     },
@@ -253,7 +289,8 @@
         "-Xsuper-fast",
         "-XepDisableAllChecks",
     ]`,
-				"srcs": `["a.java"]`,
+				"srcs":        `["a.java"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -266,14 +303,15 @@
 		ModuleTypeUnderTest:        "java_library",
 		ModuleTypeUnderTestFactory: java.LibraryFactory,
 		Blueprint: `java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			"a.logtag",
-			"b.logtag",
-		],
-        bazel_module: { bp2build_available: true },
+	name: "example_lib",
+	srcs: [
+		"a.java",
+		"b.java",
+		"a.logtag",
+		"b.logtag",
+	],
+	sdk_version: "current",
+	bazel_module: { bp2build_available: true },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("event_log_tags", "example_lib_logtags", AttrNameToString{
@@ -288,6 +326,7 @@
         "b.java",
         ":example_lib_logtags",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 		}})
@@ -301,9 +340,10 @@
 			"adir/res/b.res":      "",
 			"adir/res/dir1/b.res": "",
 			"adir/Android.bp": `java_library {
-    name: "java-lib-1",
-    java_resources: ["res/a.res", "res/b.res"],
-    bazel_module: { bp2build_available: true },
+	name: "java-lib-1",
+	java_resources: ["res/a.res", "res/b.res"],
+	sdk_version: "current",
+	bazel_module: { bp2build_available: true },
 }`,
 		},
 		Blueprint: "",
@@ -314,6 +354,7 @@
         "res/b.res",
     ]`,
 				"resource_strip_prefix": `"adir"`,
+				"sdk_version":           `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -328,8 +369,9 @@
 			"res/dir1/b.res": "",
 		},
 		Blueprint: `java_library {
-    name: "java-lib-1",
+	name: "java-lib-1",
 	java_resource_dirs: ["res"],
+	sdk_version: "current",
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
@@ -339,6 +381,7 @@
         "res/b.res",
         "res/dir1/b.res",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -352,14 +395,16 @@
 			"res/exclude/b.res": "",
 		},
 		Blueprint: `java_library {
-    name: "java-lib-1",
+	name: "java-lib-1",
 	java_resource_dirs: ["res"],
+	sdk_version: "current",
 	exclude_java_resource_dirs: ["res/exclude"],
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
 				"resource_strip_prefix": `"res"`,
 				"resources":             `["res/a.res"]`,
+				"sdk_version":           `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -374,8 +419,9 @@
 			"res/dir1/exclude.res": "",
 		},
 		Blueprint: `java_library {
-    name: "java-lib-1",
+	name: "java-lib-1",
 	java_resource_dirs: ["res"],
+	sdk_version: "current",
 	exclude_java_resources: ["res/dir1/exclude.res"],
 }`,
 		ExpectedBazelTargets: []string{
@@ -385,24 +431,68 @@
         "res/a.res",
         "res/dir1/b.res",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
 	})
 }
 
-func TestJavaLibraryResourcesFailsWithMultipleDirs(t *testing.T) {
+func TestJavaLibraryResourcesWithMultipleDirs(t *testing.T) {
 	runJavaLibraryTestCase(t, Bp2buildTestCase{
 		Filesystem: map[string]string{
-			"res/a.res":  "",
-			"res1/a.res": "",
+			"res/a.res":   "",
+			"res1/b.res":  "",
+			"res2/b.java": "",
 		},
 		Blueprint: `java_library {
-    name: "java-lib-1",
-	java_resource_dirs: ["res", "res1"],
+	name: "java-lib-1",
+	java_resource_dirs: ["res", "res1", "res2"],
+	sdk_version: "current",
 }`,
-		ExpectedErr:          fmt.Errorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)"),
-		ExpectedBazelTargets: []string{},
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_resources", "java-lib-1_resource_dir_res1", AttrNameToString{
+				"resource_strip_prefix": `"res1"`,
+				"resources":             `["res1/b.res"]`,
+			}),
+			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+				"additional_resources":  `["java-lib-1_resource_dir_res1"]`,
+				"resources":             `["res/a.res"]`,
+				"resource_strip_prefix": `"res"`,
+				"sdk_version":           `"current"`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+		},
+	})
+}
+
+func TestJavaLibraryJavaResourcesAndResourceDirs(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
+			"resdir/a.res": "",
+		},
+		Blueprint: `java_library {
+		name: "java-lib-1",
+		java_resources: ["res1", "res2"],
+		java_resource_dirs: ["resdir"],
+		sdk_version: "current",
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_resources", "java-lib-1_resource_dir_resdir", AttrNameToString{
+				"resource_strip_prefix": `"resdir"`,
+				"resources":             `["resdir/a.res"]`,
+			}),
+			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+				"additional_resources":  `["java-lib-1_resource_dir_resdir"]`,
+				"resource_strip_prefix": `"."`,
+				"resources": `[
+        "res1",
+        "res2",
+    ]`,
+				"sdk_version": `"current"`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+		},
 	})
 }
 
@@ -412,14 +502,15 @@
 		ModuleTypeUnderTest:        "java_library",
 		ModuleTypeUnderTestFactory: java.LibraryFactory,
 		Blueprint: `java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			"a.aidl",
-			"b.aidl",
-		],
-        bazel_module: { bp2build_available: true },
+	name: "example_lib",
+	srcs: [
+		"a.java",
+		"b.java",
+		"a.aidl",
+		"b.aidl",
+	],
+	bazel_module: { bp2build_available: true },
+	sdk_version: "current",
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
@@ -438,6 +529,7 @@
         "a.java",
         "b.java",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 		}})
@@ -450,12 +542,13 @@
 		ModuleTypeUnderTestFactory: java.LibraryFactory,
 		Blueprint: `
 java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.aidl",
-		],
-        bazel_module: { bp2build_available: true },
+	name: "example_lib",
+	srcs: [
+		"a.java",
+		"b.aidl",
+	],
+	sdk_version: "current",
+	bazel_module: { bp2build_available: true },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("aidl_library", "example_lib_aidl_library", AttrNameToString{
@@ -465,9 +558,10 @@
 				"deps": `[":example_lib_aidl_library"]`,
 			}),
 			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
-				"deps":    `[":example_lib_java_aidl_library"]`,
-				"exports": `[":example_lib_java_aidl_library"]`,
-				"srcs":    `["a.java"]`,
+				"deps":        `[":example_lib_java_aidl_library"]`,
+				"exports":     `[":example_lib_java_aidl_library"]`,
+				"srcs":        `["a.java"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 		},
@@ -497,14 +591,15 @@
 	],
 }
 java_library {
-        name: "example_lib",
-        srcs: [
-			"a.java",
-			"b.java",
-			":aidl_files",
-			":random_other_files",
-		],
-        bazel_module: { bp2build_available: true },
+	name: "example_lib",
+	srcs: [
+		"a.java",
+		"b.java",
+		":aidl_files",
+		":random_other_files",
+	],
+	sdk_version: "current",
+	bazel_module: { bp2build_available: true },
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions("aidl_library", "aidl_files", AttrNameToString{
@@ -525,6 +620,7 @@
         "b.java",
         ":random_other_files",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 			MakeBazelTargetNoRestrictions("filegroup", "random_other_files", AttrNameToString{
@@ -547,24 +643,26 @@
 		Filesystem: map[string]string{
 			"path/to/A/Android.bp": `
 filegroup {
-	name: "A_aidl",
-	srcs: ["aidl/A.aidl"],
-	path: "aidl",
+  name: "A_aidl",
+  srcs: ["aidl/A.aidl"],
+  path: "aidl",
 }`,
 		},
 		Blueprint: `
 java_library {
-	name: "foo",
-	srcs: [
-		":A_aidl",
-	],
+  name: "foo",
+  srcs: [
+    ":A_aidl",
+  ],
+  sdk_version: "current",
 }`,
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("java_aidl_library", "foo_java_aidl_library", AttrNameToString{
 				"deps": `["//path/to/A:A_aidl"]`,
 			}),
 			MakeBazelTarget("java_library", "foo", AttrNameToString{
-				"exports": `[":foo_java_aidl_library"]`,
+				"exports":     `[":foo_java_aidl_library"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "foo"),
 		},
@@ -579,18 +677,19 @@
 		Description:                "Android Library - simple arch feature",
 		ModuleTypeUnderTest:        "android_library",
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			neon: {
-				srcs: ["arm_neon.java"],
-			},
-		},
-	},
+  name: "TestLib",
+  manifest: "manifest/AndroidManifest.xml",
+  srcs: ["lib.java"],
+  sdk_version: "current",
+  arch: {
+    arm: {
+      neon: {
+        srcs: ["arm_neon.java"],
+      },
+    },
+  },
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -604,6 +703,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -615,21 +715,22 @@
 		Description:                "Android Library - multiple arch features",
 		ModuleTypeUnderTest:        "android_library",
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		x86: {
-			ssse3: {
-				srcs: ["ssse3.java"],
-			},
-			sse4_1: {
-				srcs: ["sse4_1.java"],
-			},
-		},
-	},
+  name: "TestLib",
+  manifest: "manifest/AndroidManifest.xml",
+  srcs: ["lib.java"],
+  sdk_version: "current",
+  arch: {
+    x86: {
+      ssse3: {
+        srcs: ["ssse3.java"],
+      },
+      sse4_1: {
+        srcs: ["sse4_1.java"],
+      },
+    },
+  },
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -648,6 +749,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`,
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -659,19 +761,20 @@
 		Description:                "Android Library - exclude_srcs with arch feature",
 		ModuleTypeUnderTest:        "android_library",
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
-		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
+		Blueprint: SimpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			srcs: ["arm_non_neon.java"],
-			neon: {
-				exclude_srcs: ["arm_non_neon.java"],
-			},
-		},
-	},
+  name: "TestLib",
+  manifest: "manifest/AndroidManifest.xml",
+  srcs: ["lib.java"],
+  arch: {
+    arm: {
+      srcs: ["arm_non_neon.java"],
+      neon: {
+        exclude_srcs: ["arm_non_neon.java"],
+      },
+    },
+  },
+  sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -686,6 +789,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -698,6 +802,7 @@
     name: "java-lib-1",
     srcs: ["a.java", "b.java", "c.kt"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -707,6 +812,7 @@
         "b.java",
         "c.kt",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -721,6 +827,7 @@
     srcs: [ "a.kt"],
     kotlincflags: ["-flag1", "-flag2"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -730,6 +837,7 @@
         "-flag1",
         "-flag2",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -744,6 +852,7 @@
     srcs: ["a.java", "b.java"],
     common_srcs: ["c.kt"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -753,6 +862,7 @@
         "b.java",
     ]`,
 				"common_srcs": `["c.kt"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -766,6 +876,7 @@
     name: "java-lib-1",
     srcs: ["a.java"],
     libs: ["java-lib-2"],
+    sdk_version: "current",
     target: {
         android: {
             libs: ["java-lib-3"],
@@ -775,16 +886,19 @@
     bazel_module: { bp2build_available: true },
 }
 
-	java_library{
-		name: "java-lib-2",
+  java_library{
+    name: "java-lib-2",
+    bazel_module: { bp2build_available: false },
 }
 
-	java_library{
-		name: "java-lib-3",
+  java_library{
+    name: "java-lib-3",
+    bazel_module: { bp2build_available: false },
 }
 
-	java_library{
-		name: "java-lib-4",
+  java_library{
+    name: "java-lib-4",
+    bazel_module: { bp2build_available: false },
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -801,14 +915,9 @@
         ],
         "//conditions:default": [],
     })`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
-			MakeBazelTarget("java_library", "java-lib-2", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-2"),
-			MakeBazelTarget("java_library", "java-lib-3", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-3"),
-			MakeBazelTarget("java_library", "java-lib-4", AttrNameToString{}),
-			MakeNeverlinkDuplicateTarget("java_library", "java-lib-4"),
 		},
 	})
 }
@@ -819,6 +928,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java", "b.java"],
+    sdk_version: "current",
     target: {
         android: {
             exclude_srcs: ["a.java"],
@@ -833,6 +943,7 @@
         "//build/bazel/platforms/os:android": [],
         "//conditions:default": ["a.java"],
     })`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -850,6 +961,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
+    sdk_version: "current",
     java_resources: [":filegroup1"],
     bazel_module: { bp2build_available: true },
 }
@@ -866,6 +978,7 @@
 				"srcs":                  `["a.java"]`,
 				"resources":             `[":filegroup1"]`,
 				"resource_strip_prefix": `"foo"`,
+				"sdk_version":           `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 			MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{
@@ -878,3 +991,70 @@
 		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	})
 }
+
+func TestJavaLibraryJavaResourcesMultipleFilegroup(t *testing.T) {
+	runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+		Filesystem: map[string]string{
+			"a.res": "",
+		},
+		Description: "with java_resources that has multiple filegroups",
+		Blueprint: `java_library {
+    name: "java-lib-1",
+    srcs: ["a.java"],
+    java_resources: ["a.res", ":filegroup1", ":filegroup2"],
+    sdk_version: "current",
+    bazel_module: { bp2build_available: true },
+}
+
+filegroup {
+    name: "filegroup1",
+    path: "foo",
+    srcs: ["foo/a"],
+}
+
+filegroup {
+    name: "filegroup2",
+    path: "bar",
+    srcs: ["bar/a"],
+}
+`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("java_resources", "java-lib-1_filegroup_resources_filegroup1", AttrNameToString{
+				"resource_strip_prefix": `"foo"`,
+				"resources":             `[":filegroup1"]`,
+			}),
+			MakeBazelTarget("java_resources", "java-lib-1_filegroup_resources_filegroup2", AttrNameToString{
+				"resource_strip_prefix": `"bar"`,
+				"resources":             `[":filegroup2"]`,
+			}),
+			MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+				"srcs":                  `["a.java"]`,
+				"resources":             `["a.res"]`,
+				"resource_strip_prefix": `"."`,
+				"additional_resources": `[
+        "java-lib-1_filegroup_resources_filegroup1",
+        "java-lib-1_filegroup_resources_filegroup2",
+    ]`,
+				"sdk_version": `"current"`,
+			}),
+			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+			MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{
+				"srcs": `["foo/a"]`}),
+			MakeBazelTargetNoRestrictions("filegroup", "filegroup2", AttrNameToString{
+				"srcs": `["bar/a"]`}),
+		},
+	}, func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+	})
+}
+
+func TestJavaSdkVersionCorePlatformDoesNotConvert(t *testing.T) {
+	runJavaLibraryTestCase(t, Bp2buildTestCase{
+		Blueprint: `java_library {
+    name: "java-lib-1",
+    sdk_version: "core_platform",
+    bazel_module: { bp2build_available: true },
+}`,
+		ExpectedBazelTargets: []string{},
+	})
+}
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index f546cf4..5d6b088 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -68,6 +68,7 @@
         type: "%s",
     },
     srcs: ["a.proto"],
+    sdk_version: "current",
 }`
 
 	protoLibrary := MakeBazelTarget("proto_library", "java-protos_proto", AttrNameToString{
@@ -86,10 +87,12 @@
 					tc.javaLibraryType,
 					javaLibraryName,
 					AttrNameToString{
-						"deps": `[":java-protos_proto"]`,
+						"deps":        `[":java-protos_proto"]`,
+						"sdk_version": `"current"`,
 					}),
 				MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-					"exports": fmt.Sprintf(`[":%s"]`, javaLibraryName),
+					"exports":     fmt.Sprintf(`[":%s"]`, javaLibraryName),
+					"sdk_version": `"current"`,
 				}),
 				MakeNeverlinkDuplicateTarget("java_library", "java-protos"),
 			},
@@ -104,6 +107,7 @@
     name: "java-protos",
     srcs: ["a.proto"],
     java_version: "7",
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -116,15 +120,20 @@
 				AttrNameToString{
 					"deps":         `[":java-protos_proto"]`,
 					"java_version": `"7"`,
+					"sdk_version":  `"current"`,
 				}),
 			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
 				"exports":      `[":java-protos_java_proto_lite"]`,
 				"java_version": `"7"`,
+				"sdk_version":  `"current"`,
 			}),
 			MakeNeverlinkDuplicateTargetWithAttrs(
 				"java_library",
 				"java-protos",
-				AttrNameToString{"java_version": `"7"`}),
+				AttrNameToString{
+					"java_version": `"7"`,
+					"sdk_version":  `"current"`,
+				}),
 		},
 	})
 }
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 00f21c8..20002c6 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -9,11 +9,17 @@
 	"android/soong/android"
 	"android/soong/shared"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
+
 	"google.golang.org/protobuf/proto"
 
 	"github.com/google/blueprint"
 )
 
+type moduleInfo struct {
+	Name string `json:"name"`
+	Type string `json:"type"`
+}
+
 // CodegenMetrics represents information about the Blueprint-to-BUILD
 // conversion process.
 // Use CreateCodegenMetrics() to get a properly initialized instance
@@ -30,6 +36,9 @@
 	// Map of converted modules and paths to call
 	// NOTE: NOT in the .proto
 	convertedModulePathMap map[string]string
+
+	// Name and type of converted modules
+	convertedModuleWithType []moduleInfo
 }
 
 func CreateCodegenMetrics() CodegenMetrics {
@@ -191,6 +200,10 @@
 	// Undo prebuilt_ module name prefix modifications
 	moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
 	metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
+	metrics.convertedModuleWithType = append(metrics.convertedModuleWithType, moduleInfo{
+		moduleName,
+		moduleType,
+	})
 	metrics.convertedModulePathMap[moduleName] = "//" + dir
 	metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
 	metrics.serialized.TotalModuleTypeCount[moduleType] += 1
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index aa0a5b7..e237303 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -149,7 +149,7 @@
 			MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
 				"filename": `"tz_version"`,
 				"src": `select({
-        "//build/bazel/product_variables:native_coverage": "src1",
+        "//build/bazel/product_config/config_settings:native_coverage": "src1",
         "//conditions:default": "version/tz_version",
     })`,
 				"dir": `"etc"`,
@@ -318,7 +318,7 @@
 				"dir":      `"etc"`,
 				"src": `select({
         "//build/bazel/platforms/arch:arm": "armSrc",
-        "//build/bazel/product_variables:native_coverage-arm": "nativeCoverageArmSrc",
+        "//build/bazel/product_config/config_settings:native_coverage-arm": "nativeCoverageArmSrc",
         "//conditions:default": None,
     })`,
 			})}})
@@ -346,3 +346,17 @@
 		ExpectedErr: fmt.Errorf("label attribute could not be collapsed"),
 	})
 }
+
+func TestPrebuiltEtcNoConversionIfSrcEqualsName(t *testing.T) {
+	runPrebuiltEtcTestCase(t, Bp2buildTestCase{
+		Description: "",
+		Filesystem:  map[string]string{},
+		Blueprint: `
+prebuilt_etc {
+    name: "foo",
+    filename: "fooFilename",
+		src: "foo",
+}`,
+		ExpectedBazelTargets: []string{},
+	})
+}
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 1b538d0..4ccdba7 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -298,8 +298,8 @@
         "r1",
         "r2",
     ],
-}` + simpleModuleDoNotConvertBp2build("genrule", "r1") +
-			simpleModuleDoNotConvertBp2build("genrule", "r2"),
+}` + SimpleModuleDoNotConvertBp2build("genrule", "r1") +
+			SimpleModuleDoNotConvertBp2build("genrule", "r2"),
 
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("py_binary", "foo", AttrNameToString{
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
index a53371d..595acd2 100644
--- a/bp2build/python_library_conversion_test.go
+++ b/bp2build/python_library_conversion_test.go
@@ -348,3 +348,43 @@
 		},
 	})
 }
+
+func TestPythonLibraryWithProtobufsAndPkgPath(t *testing.T) {
+	t.Parallel()
+	runBp2BuildTestCaseWithPythonLibraries(t, Bp2buildTestCase{
+		Description: "test python_library protobuf with pkg_path",
+		Filesystem: map[string]string{
+			"dir/foo.proto": "",
+			"dir/bar.proto": "", // bar contains "import dir/foo.proto"
+			"dir/Android.bp": `
+python_library {
+  name: "foo",
+  pkg_path: "dir",
+  srcs: [
+    "foo.proto",
+    "bar.proto",
+  ],
+  bazel_module: {bp2build_available: true},
+}`,
+		},
+		Dir: "dir",
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+				"import_prefix":       `"dir"`,
+				"strip_import_prefix": `""`,
+				"srcs": `[
+        "foo.proto",
+        "bar.proto",
+    ]`,
+			}),
+			MakeBazelTarget("py_proto_library", "foo_py_proto", AttrNameToString{
+				"deps": `[":foo_proto"]`,
+			}),
+			MakeBazelTarget("py_library", "foo", AttrNameToString{
+				"srcs_version": `"PY3"`,
+				"imports":      `[".."]`,
+				"deps":         `[":foo_py_proto"]`,
+			}),
+		},
+	})
+}
diff --git a/bp2build/rust_binary_conversion_test.go b/bp2build/rust_binary_conversion_test.go
new file mode 100644
index 0000000..a5abbdb
--- /dev/null
+++ b/bp2build/rust_binary_conversion_test.go
@@ -0,0 +1,88 @@
+// 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 runRustBinaryTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerRustBinaryModuleTypes, tc)
+}
+
+func registerRustBinaryModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("rust_binary_host", rust.RustBinaryHostFactory)
+	ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory)
+	ctx.RegisterModuleType("rust_proc_macro", rust.ProcMacroFactory)
+
+}
+
+func TestRustBinaryHost(t *testing.T) {
+	runRustBinaryTestCase(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_binary_host {
+	name: "libfoo",
+	crate_name: "foo",
+	srcs: ["src/main.rs"],
+	edition: "2021",
+	features: ["bah-enabled"],
+	cfgs: ["baz"],
+	rustlibs: ["libbar"],
+	proc_macros: ["libbah"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+			"external/rust/crates/bar/Android.bp": `
+rust_library_host {
+	name: "libbar",
+	crate_name: "bar",
+	srcs: ["src/lib.rs"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+			"external/rust/crates/bah/Android.bp": `
+rust_proc_macro {
+	name: "libbah",
+	crate_name: "bah",
+	srcs: ["src/lib.rs"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			makeBazelTargetHostOrDevice("rust_binary", "libfoo", AttrNameToString{
+				"crate_name": `"foo"`,
+				"srcs": `[
+        "src/helper.rs",
+        "src/lib.rs",
+    ]`,
+				"deps":            `["//external/rust/crates/bar:libbar"]`,
+				"proc_macro_deps": `["//external/rust/crates/bah:libbah"]`,
+				"edition":         `"2021"`,
+				"crate_features":  `["bah-enabled"]`,
+				"rustc_flags":     `["--cfg=baz"]`,
+			}, android.HostSupported),
+		},
+	},
+	)
+}
diff --git a/bp2build/rust_library_conversion_test.go b/bp2build/rust_library_conversion_test.go
new file mode 100644
index 0000000..0bc80df
--- /dev/null
+++ b/bp2build/rust_library_conversion_test.go
@@ -0,0 +1,110 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/rust"
+	"testing"
+)
+
+func runRustLibraryTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerRustLibraryModuleTypes, tc)
+}
+
+func registerRustLibraryModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("rust_library", rust.RustLibraryFactory)
+	ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory)
+}
+
+func TestLibProtobuf(t *testing.T) {
+	runRustLibraryTestCase(t, Bp2buildTestCase{
+		Dir:       "external/rust/crates/foo",
+		Blueprint: "",
+		Filesystem: map[string]string{
+			"external/rust/crates/foo/src/lib.rs": "",
+			"external/rust/crates/foo/Android.bp": `
+rust_library_host {
+	name: "libprotobuf",
+	crate_name: "protobuf",
+	srcs: ["src/lib.rs"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			// TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented
+			makeBazelTargetHostOrDevice("rust_library", "libprotobuf", AttrNameToString{
+				"crate_name": `"protobuf"`,
+				"srcs":       `["src/lib.rs"]`,
+				"deps":       `[":libprotobuf_build_script"]`,
+			}, android.HostSupported),
+			makeBazelTargetHostOrDevice("cargo_build_script", "libprotobuf_build_script", AttrNameToString{
+				"srcs": `["build.rs"]`,
+			}, android.HostSupported),
+		},
+	},
+	)
+}
+
+func TestRustLibrary(t *testing.T) {
+	expectedAttrs := AttrNameToString{
+		"crate_name": `"foo"`,
+		"srcs": `[
+        "src/helper.rs",
+        "src/lib.rs",
+    ]`,
+		"crate_features": `["bah-enabled"]`,
+		"edition":        `"2021"`,
+		"rustc_flags":    `["--cfg=baz"]`,
+	}
+
+	runRustLibraryTestCase(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_library {
+	name: "libfoo",
+	crate_name: "foo",
+    host_supported: true,
+	srcs: ["src/lib.rs"],
+	edition: "2021",
+	features: ["bah-enabled"],
+	cfgs: ["baz"],
+    bazel_module: { bp2build_available: true },
+}
+rust_library_host {
+    name: "libfoo_host",
+    crate_name: "foo",
+    srcs: ["src/lib.rs"],
+    edition: "2021",
+    features: ["bah-enabled"],
+    cfgs: ["baz"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+		},
+		ExpectedBazelTargets: []string{
+			// TODO(b/290790800): Remove the restriction when rust toolchain for android is implemented
+			makeBazelTargetHostOrDevice("rust_library", "libfoo", expectedAttrs, android.HostSupported),
+			makeBazelTargetHostOrDevice("rust_library", "libfoo_host", expectedAttrs, android.HostSupported),
+		},
+	},
+	)
+}
diff --git a/bp2build/rust_proc_macro_conversion_test.go b/bp2build/rust_proc_macro_conversion_test.go
new file mode 100644
index 0000000..7df37ec
--- /dev/null
+++ b/bp2build/rust_proc_macro_conversion_test.go
@@ -0,0 +1,76 @@
+// 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 rustRustProcMacroTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerRustProcMacroModuleTypes, tc)
+}
+
+func registerRustProcMacroModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("rust_library_host", rust.RustLibraryHostFactory)
+	ctx.RegisterModuleType("rust_proc_macro", rust.ProcMacroFactory)
+}
+
+func TestRustProcMacroLibrary(t *testing.T) {
+	rustRustProcMacroTestCase(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_proc_macro {
+	name: "libfoo",
+	crate_name: "foo",
+	srcs: ["src/lib.rs"],
+	edition: "2021",
+	features: ["bah-enabled"],
+	cfgs: ["baz"],
+	rustlibs: ["libbar"],
+    bazel_module: { bp2build_available: true },
+}
+`,
+			"external/rust/crates/bar/src/lib.rs": "",
+			"external/rust/crates/bar/Android.bp": `
+rust_library_host {
+    name: "libbar",
+    crate_name: "bar",
+    srcs: ["src/lib.rs"],
+    bazel_module: { bp2build_available: true },
+}`,
+		},
+		ExpectedBazelTargets: []string{
+			makeBazelTargetHostOrDevice("rust_proc_macro", "libfoo", AttrNameToString{
+				"crate_name": `"foo"`,
+				"srcs": `[
+        "src/helper.rs",
+        "src/lib.rs",
+    ]`,
+				"crate_features": `["bah-enabled"]`,
+				"edition":        `"2021"`,
+				"rustc_flags":    `["--cfg=baz"]`,
+				"deps":           `["//external/rust/crates/bar:libbar"]`,
+			}, android.HostSupported),
+		},
+	},
+	)
+}
diff --git a/bp2build/rust_protobuf_conversion_test.go b/bp2build/rust_protobuf_conversion_test.go
new file mode 100644
index 0000000..cf256aa
--- /dev/null
+++ b/bp2build/rust_protobuf_conversion_test.go
@@ -0,0 +1,60 @@
+// 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 runRustProtobufTestCase(t *testing.T, tc Bp2buildTestCase) {
+	t.Helper()
+	RunBp2BuildTestCase(t, registerRustProtobufModuleTypes, tc)
+}
+
+func registerRustProtobufModuleTypes(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("rust_protobuf_host", rust.RustProtobufHostFactory)
+
+}
+
+func TestRustProtobufHostTestCase(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_host {
+	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
new file mode 100644
index 0000000..e99d566
--- /dev/null
+++ b/bp2build/sh_test_conversion_test.go
@@ -0,0 +1,186 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/sh"
+)
+
+func TestShTestSimple(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+		Description:                "sh_test test",
+		ModuleTypeUnderTest:        "sh_test",
+		ModuleTypeUnderTestFactory: sh.ShTestFactory,
+		Blueprint: `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: false,
+    test_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs": `["empty.sh"]`,
+				"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",
+    ]`,
+				"test_config":          `"art-gtests-target-install-apex.xml"`,
+				"test_config_template": `":art-run-test-target-template"`,
+				"auto_gen_config":      "False",
+				"tags":                 `["no-remote"]`,
+			})},
+	})
+}
+
+func TestShTestHostSimple(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+		Description:                "sh_test_host test",
+		ModuleTypeUnderTest:        "sh_test_host",
+		ModuleTypeUnderTestFactory: sh.ShTestHostFactory,
+		Blueprint: `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: false,
+    test_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs": `["empty.sh"]`,
+				"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",
+    ]`,
+				"tags":                 `["no-remote"]`,
+				"test_config":          `"art-gtests-target-install-apex.xml"`,
+				"test_config_template": `":art-run-test-target-template"`,
+				"auto_gen_config":      "False",
+				"target_compatible_with": `select({
+        "//build/bazel/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",
+		ModuleTypeUnderTestFactory: sh.ShTestFactory,
+		Blueprint: `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_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs": `["empty.sh"]`,
+				"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",
+    ]`,
+				"tags": `["no-remote"]`,
+			})},
+	})
+}
+
+func TestShTestHostSimpleUnset(t *testing.T) {
+	RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, Bp2buildTestCase{
+		Description:                "sh_test_host test",
+		ModuleTypeUnderTest:        "sh_test_host",
+		ModuleTypeUnderTestFactory: sh.ShTestHostFactory,
+		Blueprint: `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_options:{tags: ["no-remote"],
+	},
+}`,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("sh_test", "sts-rootcanal-sidebins", AttrNameToString{
+				"srcs": `["empty.sh"]`,
+				"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",
+    ]`,
+				"tags": `["no-remote"]`,
+				"target_compatible_with": `select({
+        "//build/bazel/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 813773d..8302ce8 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -91,7 +91,7 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
         "//conditions:default": ["-DDEFAULT1"],
     }),
     local_includes = ["."],
@@ -140,7 +140,7 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
         "//conditions:default": ["-DDEFAULT1"],
     }),
     local_includes = ["."],
@@ -191,9 +191,9 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
+        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
         "//conditions:default": ["-DSOC_DEFAULT"],
     }),
     local_includes = ["."],
@@ -240,7 +240,7 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
         "//conditions:default": ["-DDEFAULT1"],
     }),
     local_includes = ["."],
@@ -310,15 +310,15 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
+        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
         "//conditions:default": ["-DSOC_DEFAULT"],
     }) + select({
-        "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+        "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
         "//conditions:default": ["-DDEFAULT1"],
     }) + select({
-        "//build/bazel/product_variables:acme__feature2": ["-DFEATURE2"],
+        "//build/bazel/product_config/config_settings:acme__feature2": ["-DFEATURE2"],
         "//conditions:default": ["-DDEFAULT2"],
     }),
     local_includes = ["."],
@@ -380,15 +380,15 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "foo",
     copts = select({
-        "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
+        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
         "//conditions:default": ["-DSOC_DEFAULT"],
     }),
     implementation_deps = select({
-        "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
-        "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
-        "//build/bazel/product_variables:acme__board__soc_c": [],
+        "//build/bazel/product_config/config_settings:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
+        "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
         "//conditions:default": ["//foo/bar:soc_default_static_dep"],
     }),
     local_includes = ["."],
@@ -446,7 +446,7 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     copts = select({
-        "//build/bazel/product_variables:vendor_foo__feature": [
+        "//build/bazel/product_config/config_settings:vendor_foo__feature": [
             "-cflag_feature_2",
             "-cflag_feature_1",
         ],
@@ -527,11 +527,11 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     asflags = select({
-        "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
+        "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
         "//conditions:default": ["-asflag_default_bar"],
     }),
     copts = select({
-        "//build/bazel/product_variables:acme__feature": [
+        "//build/bazel/product_config/config_settings:acme__feature": [
             "-cflag_foo",
             "-cflag_bar",
         ],
@@ -546,11 +546,11 @@
 			`cc_library_static(
     name = "lib2",
     asflags = select({
-        "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
+        "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
         "//conditions:default": ["-asflag_default_bar"],
     }),
     copts = select({
-        "//build/bazel/product_variables:acme__feature": [
+        "//build/bazel/product_config/config_settings:acme__feature": [
             "-cflag_bar",
             "-cflag_foo",
         ],
@@ -643,13 +643,13 @@
 		ExpectedBazelTargets: []string{`cc_library_static(
     name = "lib",
     copts = select({
-        "//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
+        "//build/bazel/product_config/config_settings:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
         "//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
     }) + select({
-        "//build/bazel/product_variables:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
+        "//build/bazel/product_config/config_settings:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
         "//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
     }) + select({
-        "//build/bazel/product_variables:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
+        "//build/bazel/product_config/config_settings:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
         "//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
     }),
     local_includes = ["."],
@@ -697,7 +697,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTarget("custom", "foo", AttrNameToString{
 				"string_literal_prop": `select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "29",
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "29",
         "//conditions:default": "30",
     })`,
 			}),
@@ -779,7 +779,7 @@
 		ExpectedBazelTargets: []string{`cc_binary(
     name = "library_linking_strategy_sample_binary",
     dynamic_deps = select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
         "//conditions:default": [
             "//foo/bar:lib_b",
             "//foo/bar:lib_a",
@@ -868,7 +868,7 @@
 		ExpectedBazelTargets: []string{
 			MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary", AttrNameToString{
 				"dynamic_deps": `select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
         "//conditions:default": [
             "//foo/bar:lib_b",
             "//foo/bar:lib_c",
@@ -877,7 +877,7 @@
 			}),
 			MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary_with_excludes", AttrNameToString{
 				"dynamic_deps": `select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
         "//conditions:default": ["//foo/bar:lib_b"],
     })`,
 			}),
@@ -965,14 +965,14 @@
 		ExpectedBazelTargets: []string{`cc_binary(
     name = "library_linking_strategy_sample_binary",
     deps = select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
             "//foo/bar:lib_b_bp2build_cc_library_static",
             "//foo/bar:lib_a_bp2build_cc_library_static",
         ],
         "//conditions:default": [],
     }),
     dynamic_deps = select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
         "//conditions:default": [
             "//foo/bar:lib_b",
             "//foo/bar:lib_a",
@@ -1046,14 +1046,14 @@
 		ExpectedBazelTargets: []string{`cc_binary(
     name = "library_linking_strategy_sample_binary",
     deps = select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
             "//foo/bar:lib_a_bp2build_cc_library_static",
             "//foo/bar:lib_b_bp2build_cc_library_static",
         ],
         "//conditions:default": [],
     }),
     dynamic_deps = select({
-        "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+        "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
         "//conditions:default": [
             "//foo/bar:lib_a",
             "//foo/bar:lib_b",
@@ -1134,13 +1134,13 @@
 		ExpectedBazelTargets: []string{`cc_binary(
     name = "alphabet_binary",
     deps = select({
-        "//build/bazel/product_variables:android__alphabet__a": [],
-        "//build/bazel/product_variables:android__alphabet__b": [],
+        "//build/bazel/product_config/config_settings:android__alphabet__a": [],
+        "//build/bazel/product_config/config_settings:android__alphabet__b": [],
         "//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
     }),
     dynamic_deps = select({
-        "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"],
-        "//build/bazel/product_variables:android__alphabet__b": ["//foo/bar:lib_b"],
+        "//build/bazel/product_config/config_settings:android__alphabet__a": ["//foo/bar:lib_a"],
+        "//build/bazel/product_config/config_settings:android__alphabet__b": ["//foo/bar:lib_b"],
         "//conditions:default": [],
     }),
     local_includes = ["."],
@@ -1199,7 +1199,7 @@
     name = "alphabet_binary",
     local_includes = ["."],
     srcs = ["main.cc"],
-    target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"] + select({
+    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"],
@@ -1208,6 +1208,9 @@
         "//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
         "//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
         "//conditions:default": [],
+    }) + select({
+        "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
+        "//conditions:default": ["@platforms//:incompatible"],
     }),
 )`}})
 }
@@ -1240,6 +1243,24 @@
     srcs: ["main.cc"],
     defaults: ["alphabet_sample_cc_defaults"],
     enabled: false,
+}
+
+alphabet_cc_defaults {
+    name: "alphabet_sample_cc_defaults_conditions_default",
+    soong_config_variables: {
+        special_build: {
+		conditions_default: {
+			enabled: false,
+		},
+	},
+    },
+}
+
+cc_binary {
+    name: "alphabet_binary_conditions_default",
+    srcs: ["main.cc"],
+    defaults: ["alphabet_sample_cc_defaults_conditions_default"],
+    enabled: false,
 }`
 
 	runSoongConfigModuleTypeTest(t, Bp2buildTestCase{
@@ -1252,8 +1273,17 @@
     name = "alphabet_binary",
     local_includes = ["."],
     srcs = ["main.cc"],
-    target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"],
-)`}})
+    target_compatible_with = select({
+        "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
+        "//conditions:default": ["@platforms//:incompatible"],
+    }),
+)`,
+			MakeBazelTarget("cc_binary", "alphabet_binary_conditions_default", AttrNameToString{
+				"local_includes":         `["."]`,
+				"srcs":                   `["main.cc"]`,
+				"target_compatible_with": `["@platforms//:incompatible"]`,
+			}),
+		}})
 }
 
 func TestSoongConfigModuleType_ProductVariableIgnoredIfEnabledByDefault(t *testing.T) {
@@ -1389,16 +1419,16 @@
         "//build/bazel/platforms/os:android": ["-DFOO"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:my_namespace__my_bool_variable__android": ["-DBAR"],
-        "//build/bazel/product_variables:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__android": ["-DBAR"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
         "//conditions:default": [],
     }) + select({
-        "//build/bazel/product_variables:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
-        "//build/bazel/product_variables:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
-        "//build/bazel/product_variables:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
         "//conditions:default": [],
     }),
     local_includes = ["."],
@@ -1406,3 +1436,166 @@
     target_compatible_with = ["//build/bazel/platforms/os:android"],
 )`}})
 }
+
+// If we have
+// A. a soong_config_module_type with target.android_<arch>.* in properties
+// B. a module that uses this module type but does not set target.android_<arch>.* via soong config vars
+// Then we should not panic
+func TestPanicsIfSoongConfigModuleTypeHasArchSpecificProperties(t *testing.T) {
+	commonBp := `
+soong_config_bool_variable {
+	name: "my_bool_variable",
+}
+soong_config_module_type {
+	name: "special_cc_defaults",
+	module_type: "cc_defaults",
+	config_namespace: "my_namespace",
+	bool_variables: ["my_bool_variable"],
+	properties: [
+		"cflags",
+		"target.android_arm64.shared_libs",
+	],
+}
+cc_binary {
+	name: "my_binary",
+	defaults: ["my_special_cc_defaults"],
+}
+`
+	testCases := []struct {
+		desc            string
+		additionalBp    string
+		isPanicExpected bool
+	}{
+		{
+			desc: "target.android_arm64 is not set, bp2build should not panic",
+			additionalBp: `
+special_cc_defaults {
+	name: "my_special_cc_defaults",
+	soong_config_variables: {
+		my_bool_variable: {
+			cflags: ["-DFOO"],
+			conditions_default: {
+				cflags: ["-DBAR"],
+			}
+		}
+	},
+}
+			`,
+			isPanicExpected: false,
+		},
+		{
+			desc: "target.android_arm64 is set using the bool soong config var, bp2build should panic",
+			additionalBp: `
+special_cc_defaults {
+	name: "my_special_cc_defaults",
+	soong_config_variables: {
+		my_bool_variable: {
+			cflags: ["-DFOO"],
+			target: {
+				android_arm64: {
+					shared_libs: ["liblog"],
+				},
+			},
+			conditions_default: {
+				cflags: ["-DBAR"],
+			}
+		}
+	},
+}
+			`,
+			isPanicExpected: true,
+		},
+		{
+			desc: "target.android_arm64 is set using conditions_default for the bool soong config var, bp2build should panic",
+			additionalBp: `
+special_cc_defaults {
+	name: "my_special_cc_defaults",
+	soong_config_variables: {
+		my_bool_variable: {
+			cflags: ["-DFOO"],
+			conditions_default: {
+				cflags: ["-DBAR"],
+				target: {
+					android_arm64: {
+						shared_libs: ["liblog"],
+					},
+				},
+			}
+		}
+	},
+}
+			`,
+			isPanicExpected: true,
+		},
+	}
+	for _, tc := range testCases {
+		bp2buildTestCase := Bp2buildTestCase{
+			Description:                tc.desc,
+			ModuleTypeUnderTest:        "cc_binary",
+			ModuleTypeUnderTestFactory: cc.BinaryFactory,
+			Blueprint:                  commonBp + tc.additionalBp,
+			// Check in `foo` dir so that we can check whether it panics or not and not trip over an empty `ExpectedBazelTargets`
+			Dir:                  "foo",
+			ExpectedBazelTargets: []string{},
+		}
+		if tc.isPanicExpected {
+			bp2buildTestCase.ExpectedErr = fmt.Errorf("TODO: support other target types in soong config variable structs: Android_arm64")
+		}
+		runSoongConfigModuleTypeTest(t, bp2buildTestCase)
+	}
+}
+
+func TestNoPanicIfEnabledIsNotUsed(t *testing.T) {
+	bp := `
+soong_config_string_variable {
+	name: "my_string_variable",
+	values: ["val1", "val2"],
+}
+soong_config_module_type {
+	name: "special_cc_defaults",
+	module_type: "cc_defaults",
+	config_namespace: "my_namespace",
+	variables: ["my_string_variable"],
+	properties: [
+		"cflags",
+		"enabled",
+	],
+}
+special_cc_defaults {
+	name: "my_special_cc_defaults",
+	soong_config_variables: {
+		my_string_variable: {
+			val1: {
+				cflags: ["-DFOO"],
+			},
+			val2: {
+				cflags: ["-DBAR"],
+			},
+		},
+	},
+}
+cc_binary {
+	name: "my_binary",
+	enabled: false,
+	defaults: ["my_special_cc_defaults"],
+}
+`
+	tc := Bp2buildTestCase{
+		Description:                "Soong config vars is not used to set `enabled` property",
+		ModuleTypeUnderTest:        "cc_binary",
+		ModuleTypeUnderTestFactory: cc.BinaryFactory,
+		Blueprint:                  bp,
+		ExpectedBazelTargets: []string{
+			MakeBazelTarget("cc_binary", "my_binary", AttrNameToString{
+				"copts": `select({
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val1": ["-DFOO"],
+        "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__val2": ["-DBAR"],
+        "//conditions:default": [],
+    })`,
+				"local_includes":         `["."]`,
+				"target_compatible_with": `["@platforms//:incompatible"]`,
+			}),
+		},
+	}
+	runSoongConfigModuleTypeTest(t, tc)
+}
diff --git a/bp2build/symlink_forest.go b/bp2build/symlink_forest.go
index 5c33308..a0c7e4c 100644
--- a/bp2build/symlink_forest.go
+++ b/bp2build/symlink_forest.go
@@ -190,10 +190,20 @@
 
 // Creates a symbolic link at dst pointing to src
 func symlinkIntoForest(topdir, dst, src string) uint64 {
-	srcPath := shared.JoinPath(topdir, src)
-	dstPath := shared.JoinPath(topdir, dst)
+	// b/259191764 - Make all symlinks relative
+	dst = shared.JoinPath(topdir, dst)
+	src = shared.JoinPath(topdir, src)
+	basePath := filepath.Dir(dst)
+	var dstPath string
+	srcPath, err := filepath.Rel(basePath, src)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Failed to find relative path for symlinking: %s\n", err)
+		os.Exit(1)
+	} else {
+		dstPath = 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)
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 140b214..0e7ef44 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -108,15 +108,6 @@
 	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
 }
 
-func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
-	t.Helper()
-	apiBp2BuildSetup := android.GroupFixturePreparers(
-		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetApiBp2BuildTestRunner,
-	)
-	runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc)
-}
-
 func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
 	t.Helper()
 	dir := "."
@@ -180,27 +171,14 @@
 }
 
 // SetBp2BuildTestRunner customizes the test fixture mechanism to run tests in Bp2Build mode.
-var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{Bp2Build})
+var SetBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{})
 
-// SetApiBp2BuildTestRunner customizes the test fixture mechanism to run tests in ApiBp2build mode.
-var SetApiBp2BuildTestRunner = android.FixtureSetTestRunner(&bazelTestRunner{ApiBp2build})
-
-// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build and
-// apiBp2build build modes.
-type bazelTestRunner struct {
-	mode CodegenMode
-}
+// bazelTestRunner customizes the test fixture mechanism to run tests of the bp2build build mode.
+type bazelTestRunner struct{}
 
 func (b *bazelTestRunner) FinalPreparer(result *android.TestResult) android.CustomTestResult {
 	ctx := result.TestContext
-	switch b.mode {
-	case Bp2Build:
-		ctx.RegisterForBazelConversion()
-	case ApiBp2build:
-		ctx.RegisterForApiBazelConversion()
-	default:
-		panic(fmt.Errorf("unknown build mode: %d", b.mode))
-	}
+	ctx.RegisterForBazelConversion()
 
 	return &BazelTestResult{TestResult: result}
 }
@@ -214,11 +192,7 @@
 		return
 	}
 
-	codegenMode := Bp2Build
-	if ctx.Config().BuildMode == android.ApiBp2build {
-		codegenMode = ApiBp2build
-	}
-	codegenCtx := NewCodegenContext(config, ctx.Context, codegenMode, "")
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
 	res, errs := GenerateBazelTargets(codegenCtx, false)
 	if bazelResult.CollateErrs(errs) {
 		return
@@ -336,6 +310,8 @@
 	Api *string // File describing the APIs of this module
 
 	Test_config_setting *bool // Used to test generation of config_setting targets
+
+	Dir *string // Dir in which the Bazel Target will be created
 }
 
 type customModule struct {
@@ -461,6 +437,10 @@
 	Api                 bazel.LabelAttribute
 }
 
+func (m *customModule) dir() *string {
+	return m.props.Dir
+}
+
 func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
@@ -508,7 +488,7 @@
 		Rule_class: "custom",
 	}
 
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name(), Dir: m.dir()}, attrs)
 
 	if proptools.Bool(m.props.Test_config_setting) {
 		m.createConfigSetting(ctx)
@@ -590,7 +570,7 @@
 	ctx.RegisterForBazelConversion()
 }
 
-func simpleModuleDoNotConvertBp2build(typ, name string) string {
+func SimpleModuleDoNotConvertBp2build(typ, name string) string {
 	return fmt.Sprintf(`
 %s {
 		name: "%s",
@@ -682,7 +662,9 @@
 }
 
 func MakeNeverlinkDuplicateTarget(moduleType string, name string) string {
-	return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{})
+	return MakeNeverlinkDuplicateTargetWithAttrs(moduleType, name, AttrNameToString{
+		"sdk_version": `"current"`, // use as default
+	})
 }
 
 func MakeNeverlinkDuplicateTargetWithAttrs(moduleType string, name string, extraAttrs AttrNameToString) string {
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 45009c1..d135d5f 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -153,7 +153,9 @@
 		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
 		"-isystem bionic/libc/kernel/uapi/asm-arm64",
 		"-isystem bionic/libc/kernel/android/uapi",
+		// TODO(b/296014682): Remove after the bpf_headers is moved to Connectivity
 		"-I       frameworks/libs/net/common/native/bpf_headers/include/bpf",
+		"-I       packages/modules/Connectivity/staticlibs/native/bpf_headers/include/bpf",
 		// TODO(b/149785767): only give access to specific file with AID_* constants
 		"-I       system/core/libcutils/include",
 		"-I " + ctx.ModuleDir(),
diff --git a/cc/Android.bp b/cc/Android.bp
index e88ea03..c32d854 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -37,6 +37,7 @@
         "linkable.go",
         "lto.go",
         "makevars.go",
+        "orderfile.go",
         "pgo.go",
         "prebuilt.go",
         "proto.go",
@@ -104,6 +105,7 @@
         "lto_test.go",
         "ndk_test.go",
         "object_test.go",
+        "orderfile_test.go",
         "prebuilt_test.go",
         "proto_test.go",
         "sanitize_test.go",
diff --git a/cc/afdo.go b/cc/afdo.go
index bc7cd52..23d196d 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -131,6 +131,10 @@
 		return
 	}
 
+	if !c.afdo.afdoEnabled() {
+		return
+	}
+
 	ctx.VisitDirectDepsWithTag(FdoProfileTag, func(m android.Module) {
 		if ctx.OtherModuleHasProvider(m, FdoProfileProvider) {
 			info := ctx.OtherModuleProvider(m, FdoProfileProvider).(FdoProfileInfo)
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ce35b5c..e0e543f 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -530,9 +530,9 @@
 
 	entries.SubName = ""
 
-	if c.isSanitizerEnabled(cfi) {
+	if c.IsSanitizerEnabled(cfi) {
 		entries.SubName += ".cfi"
-	} else if c.isSanitizerEnabled(Hwasan) {
+	} else if c.IsSanitizerEnabled(Hwasan) {
 		entries.SubName += ".hwasan"
 	}
 
diff --git a/cc/api_level.go b/cc/api_level.go
index a5571f3..69a0d3a 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -31,7 +31,11 @@
 	case android.Arm64, android.X86_64:
 		return android.FirstLp64Version
 	case android.Riscv64:
-		return android.FutureApiLevel
+		apiLevel, err := android.ApiLevelFromUser(ctx, "VanillaIceCream")
+		if err != nil {
+			panic(err)
+		}
+		return apiLevel
 	default:
 		panic(fmt.Errorf("Unknown arch %q", arch))
 	}
diff --git a/cc/binary.go b/cc/binary.go
index 5ba33a2..4606b62 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -638,7 +638,8 @@
 		Stl:               baseAttrs.stl,
 		Cpp_std:           baseAttrs.cppStd,
 
-		Additional_linker_inputs: baseAttrs.additionalLinkerInputs,
+		Additional_linker_inputs:   baseAttrs.additionalLinkerInputs,
+		Additional_compiler_inputs: baseAttrs.additionalCompilerInputs,
 
 		Strip: stripAttributes{
 			Keep_symbols:                 baseAttrs.stripKeepSymbols,
@@ -680,10 +681,11 @@
 	Srcs_c  bazel.LabelListAttribute
 	Srcs_as bazel.LabelListAttribute
 
-	Copts      bazel.StringListAttribute
-	Cppflags   bazel.StringListAttribute
-	Conlyflags bazel.StringListAttribute
-	Asflags    bazel.StringListAttribute
+	Copts                      bazel.StringListAttribute
+	Cppflags                   bazel.StringListAttribute
+	Conlyflags                 bazel.StringListAttribute
+	Asflags                    bazel.StringListAttribute
+	Additional_compiler_inputs bazel.LabelListAttribute
 
 	Deps               bazel.LabelListAttribute
 	Dynamic_deps       bazel.LabelListAttribute
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 6e00aa8..039a3cf 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -22,6 +22,7 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/cc/config"
+	"android/soong/genrule"
 
 	"github.com/google/blueprint"
 
@@ -43,6 +44,14 @@
 
 	rScriptSrcPartition = "renderScript"
 
+	xsdSrcPartition = "xsd"
+
+	genrulePartition = "genrule"
+
+	protoFromGenPartition = "proto_gen"
+
+	hdrPartition = "hdr"
+
 	stubsSuffix = "_stub_libs_current"
 )
 
@@ -56,6 +65,8 @@
 	Hdrs      bazel.LabelListAttribute
 	Copts     bazel.StringListAttribute
 
+	Additional_compiler_inputs bazel.LabelListAttribute
+
 	Deps                              bazel.LabelListAttribute
 	Implementation_deps               bazel.LabelListAttribute
 	Dynamic_deps                      bazel.LabelListAttribute
@@ -119,6 +130,41 @@
 	}
 }
 
+// Returns an unchanged label and a bool indicating whether the dep is a genrule that produces .proto files
+func protoFromGenPartitionMapper(pathCtx android.BazelConversionContext) bazel.LabelMapper {
+	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+		mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+		if !exists {
+			return label.Label, false
+		}
+		gen, isGen := mod.(*genrule.Module)
+		if !isGen {
+			return label.Label, false
+		}
+		if containsProto(ctx, gen.RawOutputFiles(pathCtx)) {
+			// Return unmodified label + true
+			// True will ensure that this module gets dropped from `srcs` of the generated cc_* target. `srcs` is reserved for .cpp files
+			return label.Label, true
+		}
+		return label.Label, false
+	}
+}
+
+// Returns true if srcs contains only .proto files
+// Raises an exception if there is a combination of .proto and non .proto srcs
+func containsProto(ctx bazel.OtherModuleContext, srcs []string) bool {
+	onlyProtos := false
+	for _, src := range srcs {
+		if strings.HasSuffix(src, ".proto") {
+			onlyProtos = true
+		} else if onlyProtos {
+			// This is not a proto file, and we have encountered a .proto file previously
+			ctx.ModuleErrorf("TOOD: Add bp2build support combination of .proto and non .proto files in outs of genrule")
+		}
+	}
+	return onlyProtos
+}
+
 // groupSrcsByExtension partitions `srcs` into groups based on file extension.
 func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
 	// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
@@ -152,9 +198,11 @@
 		// 		contains .l or .ll files we will need to find a way to add a
 		// 		LabelMapper for these that identifies these filegroups and
 		//		converts them appropriately
-		lSrcPartition:       bazel.LabelPartition{Extensions: []string{".l"}},
-		llSrcPartition:      bazel.LabelPartition{Extensions: []string{".ll"}},
-		rScriptSrcPartition: bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
+		lSrcPartition:         bazel.LabelPartition{Extensions: []string{".l"}},
+		llSrcPartition:        bazel.LabelPartition{Extensions: []string{".ll"}},
+		rScriptSrcPartition:   bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
+		xsdSrcPartition:       bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+		protoFromGenPartition: bazel.LabelPartition{LabelMapper: protoFromGenPartitionMapper(ctx)},
 		// C++ is the "catch-all" group, and comprises generated sources because we don't
 		// know the language of these sources until the genrule is executed.
 		cppSrcPartition:     bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
@@ -165,6 +213,15 @@
 	return bazel.PartitionLabelListAttribute(ctx, &srcs, labels)
 }
 
+func partitionHeaders(ctx android.BazelConversionPathContext, hdrs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
+	labels := bazel.LabelPartitions{
+		xsdSrcPartition:  bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+		genrulePartition: bazel.LabelPartition{LabelMapper: genrule.GenruleCcHeaderLabelMapper},
+		hdrPartition:     bazel.LabelPartition{Keep_remainder: true},
+	}
+	return bazel.PartitionLabelListAttribute(ctx, &hdrs, labels)
+}
+
 // bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
 func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
 	lib, ok := module.compiler.(*libraryDecorator)
@@ -403,7 +460,12 @@
 	srcs     bazel.LabelListAttribute
 
 	// xsd config sources
-	xsdInSrcs bazel.StringListAttribute
+	xsdSrcs       bazel.LabelListAttribute
+	exportXsdSrcs bazel.LabelListAttribute
+
+	// genrule headers
+	genruleHeaders       bazel.LabelListAttribute
+	exportGenruleHeaders bazel.LabelListAttribute
 
 	// Lex sources and options
 	lSrcs   bazel.LabelListAttribute
@@ -448,6 +510,8 @@
 	suffix bazel.StringAttribute
 
 	fdoProfile bazel.LabelAttribute
+
+	additionalCompilerInputs bazel.LabelListAttribute
 }
 
 type filterOutFn func(string) bool
@@ -494,14 +558,11 @@
 func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
 	// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
 	// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
-	srcsList, xsdList, ok := parseSrcs(ctx, props)
+	srcsList, ok := parseSrcs(ctx, props)
 
 	if ok {
 		ca.srcs.SetSelectValue(axis, config, srcsList)
 	}
-	if len(xsdList) > 0 {
-		ca.xsdInSrcs.SetSelectValue(axis, config, xsdList)
-	}
 
 	localIncludeDirs := props.Local_include_dirs
 	if axis == bazel.NoConfigAxis {
@@ -568,11 +629,14 @@
 	}
 }
 
-func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs bazel.LabelListAttribute) {
+func (ca *compilerAttributes) finalize(ctx android.BazelConversionPathContext, implementationHdrs, exportHdrs bazel.LabelListAttribute) {
 	ca.srcs.ResolveExcludes()
 	partitionedSrcs := groupSrcsByExtension(ctx, ca.srcs)
+	partitionedImplHdrs := partitionHeaders(ctx, implementationHdrs)
+	partitionedHdrs := partitionHeaders(ctx, exportHdrs)
 
 	ca.protoSrcs = partitionedSrcs[protoSrcPartition]
+	ca.protoSrcs.Append(partitionedSrcs[protoFromGenPartition])
 	ca.aidlSrcs = partitionedSrcs[aidlSrcPartition]
 
 	for p, lla := range partitionedSrcs {
@@ -580,10 +644,22 @@
 		if lla.IsEmpty() {
 			continue
 		}
-		lla.Append(implementationHdrs)
+		lla.Append(partitionedImplHdrs[hdrPartition])
 		partitionedSrcs[p] = lla
 	}
 
+	ca.hdrs = partitionedHdrs[hdrPartition]
+
+	ca.includesFromHeaders(ctx, partitionedImplHdrs[hdrPartition], partitionedHdrs[hdrPartition])
+
+	xsdSrcs := bazel.SubtractBazelLabelListAttribute(partitionedSrcs[xsdSrcPartition], partitionedHdrs[xsdSrcPartition])
+	xsdSrcs.Append(partitionedImplHdrs[xsdSrcPartition])
+	ca.exportXsdSrcs = partitionedHdrs[xsdSrcPartition]
+	ca.xsdSrcs = bazel.FirstUniqueBazelLabelListAttribute(xsdSrcs)
+
+	ca.genruleHeaders = partitionedImplHdrs[genrulePartition]
+	ca.exportGenruleHeaders = partitionedHdrs[genrulePartition]
+
 	ca.srcs = partitionedSrcs[cppSrcPartition]
 	ca.cSrcs = partitionedSrcs[cSrcPartition]
 	ca.asSrcs = partitionedSrcs[asSrcPartition]
@@ -604,11 +680,11 @@
 }
 
 // Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, []string, bool) {
+func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
 	anySrcs := false
 	// Add srcs-like dependencies such as generated files.
 	// First create a LabelList containing these dependencies, then merge the values with srcs.
-	genSrcs, xsd := android.PartitionXsdSrcs(ctx, props.Generated_sources)
+	genSrcs := props.Generated_sources
 	generatedSrcsLabelList := android.BazelLabelForModuleDepsExcludes(ctx, genSrcs, props.Exclude_generated_sources)
 	if len(props.Generated_sources) > 0 || len(props.Exclude_generated_sources) > 0 {
 		anySrcs = true
@@ -620,7 +696,7 @@
 		anySrcs = true
 	}
 
-	return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), xsd, anySrcs
+	return bazel.AppendBazelLabelLists(allSrcsLabelList, generatedSrcsLabelList), anySrcs
 }
 
 func bp2buildStdVal(std *string, prefix string, useGnu bool) *string {
@@ -667,8 +743,43 @@
 	return split[0][2:], true
 }
 
-// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList>
-func includesFromLabelList(labelList bazel.LabelList) (relative, absolute []string) {
+// includesFromHeaders gets the include directories needed from generated headers
+func (ca *compilerAttributes) includesFromHeaders(ctx android.BazelConversionPathContext, implHdrs, hdrs bazel.LabelListAttribute) {
+	local, absolute := includesFromLabelListAttribute(implHdrs, ca.localIncludes, ca.absoluteIncludes)
+	localExport, absoluteExport := includesFromLabelListAttribute(hdrs, ca.includes.Includes, ca.includes.AbsoluteIncludes)
+
+	ca.localIncludes = local
+	ca.absoluteIncludes = absolute
+
+	ca.includes.Includes = localExport
+	ca.includes.AbsoluteIncludes = absoluteExport
+}
+
+// includesFromLabelList extracts the packages from a LabelListAttribute that should be includes and
+// combines them with existing local/absolute includes.
+func includesFromLabelListAttribute(attr bazel.LabelListAttribute, existingLocal, existingAbsolute bazel.StringListAttribute) (bazel.StringListAttribute, bazel.StringListAttribute) {
+	localAttr := existingLocal.Clone()
+	absoluteAttr := existingAbsolute.Clone()
+	if !attr.Value.IsEmpty() {
+		l, a := includesFromLabelList(attr.Value, existingLocal.Value, existingAbsolute.Value)
+		localAttr.SetSelectValue(bazel.NoConfigAxis, "", l)
+		absoluteAttr.SetSelectValue(bazel.NoConfigAxis, "", a)
+	}
+	for axis, configToLabels := range attr.ConfigurableValues {
+		for c, labels := range configToLabels {
+			local := existingLocal.SelectValue(axis, c)
+			absolute := existingAbsolute.SelectValue(axis, c)
+			l, a := includesFromLabelList(labels, local, absolute)
+			localAttr.SetSelectValue(axis, c, l)
+			absoluteAttr.SetSelectValue(axis, c, a)
+		}
+	}
+	return *localAttr, *absoluteAttr
+}
+
+// includesFromLabelList extracts relative/absolute includes from a bazel.LabelList.
+func includesFromLabelList(labelList bazel.LabelList, existingRel, existingAbs []string) ([]string, []string) {
+	var relative, absolute []string
 	for _, hdr := range labelList.Includes {
 		if pkg, hasPkg := packageFromLabel(hdr.Label); hasPkg {
 			absolute = append(absolute, pkg)
@@ -676,6 +787,12 @@
 			relative = append(relative, pkg)
 		}
 	}
+	if len(relative)+len(existingRel) != 0 {
+		relative = android.FirstUniqueStrings(append(append([]string{}, existingRel...), relative...))
+	}
+	if len(absolute)+len(existingAbs) != 0 {
+		absolute = android.FirstUniqueStrings(append(append([]string{}, existingAbs...), absolute...))
+	}
 	return relative, absolute
 }
 
@@ -734,14 +851,12 @@
 	return ret
 }
 
-// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module..
+// bp2BuildParseBaseProps returns all compiler, linker, library attributes of a cc module.
 func bp2BuildParseBaseProps(ctx android.Bp2buildMutatorContext, module *Module) baseAttributes {
 	archVariantCompilerProps := module.GetArchVariantProperties(ctx, &BaseCompilerProperties{})
 	archVariantLinkerProps := module.GetArchVariantProperties(ctx, &BaseLinkerProperties{})
 	archVariantLibraryProperties := module.GetArchVariantProperties(ctx, &LibraryProperties{})
 
-	var implementationHdrs bazel.LabelListAttribute
-
 	axisToConfigs := map[bazel.ConfigurationAxis]map[string]bool{}
 	allAxesAndConfigs := func(cp android.ConfigurationAxisToArchVariantProperties) {
 		for axis, configMap := range cp {
@@ -761,6 +876,7 @@
 	linkerAttrs := linkerAttributes{}
 
 	var aidlLibs bazel.LabelList
+	var implementationHdrs, exportHdrs bazel.LabelListAttribute
 
 	// Iterate through these axes in a deterministic order. This is required
 	// because processing certain dependencies may result in concatenating
@@ -770,9 +886,9 @@
 	for _, axis := range bazel.SortedConfigurationAxes(axisToConfigs) {
 		configs := axisToConfigs[axis]
 		for cfg := range configs {
-			var allHdrs, allHdrsXsd []string
+			var allHdrs []string
 			if baseCompilerProps, ok := archVariantCompilerProps[axis][cfg].(*BaseCompilerProperties); ok {
-				allHdrs, allHdrsXsd = android.PartitionXsdSrcs(ctx, baseCompilerProps.Generated_headers)
+				allHdrs = baseCompilerProps.Generated_headers
 
 				if baseCompilerProps.Lex != nil {
 					compilerAttrs.lexopts.SetSelectValue(axis, cfg, baseCompilerProps.Lex.Flags)
@@ -786,36 +902,17 @@
 				aidlLibs.Append(android.BazelLabelForModuleDeps(ctx, baseCompilerProps.Aidl.Libs))
 			}
 
-			var exportHdrs, exportHdrsXsd []string
+			var exportedHdrs []string
 
 			if baseLinkerProps, ok := archVariantLinkerProps[axis][cfg].(*BaseLinkerProperties); ok {
-				exportHdrs, exportHdrsXsd = android.PartitionXsdSrcs(ctx, baseLinkerProps.Export_generated_headers)
+				exportedHdrs = baseLinkerProps.Export_generated_headers
 				(&linkerAttrs).bp2buildForAxisAndConfig(ctx, module, axis, cfg, baseLinkerProps)
 			}
 
-			// in the synthetic bp2build workspace, xsd sources are compiled to a static library
-			xsdList := compilerAttrs.xsdInSrcs.SelectValue(axis, cfg)
-			allHdrsXsd = android.FirstUniqueStrings(append(xsdList, allHdrsXsd...))
-			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportHdrs, android.BazelLabelForModuleDeps)
-			xsdConfigLibs := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrsXsd, exportHdrsXsd, bazelLabelForXsdConfig)
+			headers := maybePartitionExportedAndImplementationsDeps(ctx, !module.Binary(), allHdrs, exportedHdrs, android.BazelLabelForModuleDeps)
 
 			implementationHdrs.SetSelectValue(axis, cfg, headers.implementation)
-			compilerAttrs.hdrs.SetSelectValue(axis, cfg, headers.export)
-
-			exportIncludes, exportAbsoluteIncludes := includesFromLabelList(headers.export)
-			compilerAttrs.includes.Includes.SetSelectValue(axis, cfg, exportIncludes)
-			compilerAttrs.includes.AbsoluteIncludes.SetSelectValue(axis, cfg, exportAbsoluteIncludes)
-
-			includes, absoluteIncludes := includesFromLabelList(headers.implementation)
-			currAbsoluteIncludes := compilerAttrs.absoluteIncludes.SelectValue(axis, cfg)
-			currAbsoluteIncludes = android.FirstUniqueStrings(append(currAbsoluteIncludes, absoluteIncludes...))
-
-			compilerAttrs.absoluteIncludes.SetSelectValue(axis, cfg, currAbsoluteIncludes)
-
-			currIncludes := compilerAttrs.localIncludes.SelectValue(axis, cfg)
-			currIncludes = android.FirstUniqueStrings(append(currIncludes, includes...))
-
-			compilerAttrs.localIncludes.SetSelectValue(axis, cfg, currIncludes)
+			exportHdrs.SetSelectValue(axis, cfg, headers.export)
 
 			if libraryProps, ok := archVariantLibraryProperties[axis][cfg].(*LibraryProperties); ok {
 				if axis == bazel.NoConfigAxis {
@@ -835,14 +932,6 @@
 				}
 			}
 
-			if len(allHdrsXsd) > 0 {
-				wholeStaticLibs := linkerAttrs.implementationWholeArchiveDeps.SelectValue(axis, cfg)
-				(&wholeStaticLibs).Append(xsdConfigLibs.implementation)
-				linkerAttrs.implementationWholeArchiveDeps.SetSelectValue(axis, cfg, wholeStaticLibs)
-				wholeStaticLibs = linkerAttrs.wholeArchiveDeps.SelectValue(axis, cfg)
-				(&wholeStaticLibs).Append(xsdConfigLibs.export)
-				linkerAttrs.wholeArchiveDeps.SetSelectValue(axis, cfg, wholeStaticLibs)
-			}
 		}
 	}
 
@@ -860,12 +949,18 @@
 	(&compilerAttrs).convertProductVariables(ctx, productVariableProps)
 	(&linkerAttrs).convertProductVariables(ctx, productVariableProps)
 
-	(&compilerAttrs).finalize(ctx, implementationHdrs)
+	(&compilerAttrs).finalize(ctx, implementationHdrs, exportHdrs)
 	(&linkerAttrs).finalize(ctx)
 
 	(&compilerAttrs.srcs).Add(bp2BuildYasm(ctx, module, compilerAttrs))
 
-	protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs)
+	(&linkerAttrs).deps.Append(compilerAttrs.exportGenruleHeaders)
+	(&linkerAttrs).implementationDeps.Append(compilerAttrs.genruleHeaders)
+
+	(&linkerAttrs).wholeArchiveDeps.Append(compilerAttrs.exportXsdSrcs)
+	(&linkerAttrs).implementationWholeArchiveDeps.Append(compilerAttrs.xsdSrcs)
+
+	protoDep := bp2buildProto(ctx, module, compilerAttrs.protoSrcs, linkerAttrs)
 
 	// bp2buildProto will only set wholeStaticLib or implementationWholeStaticLib, but we don't know
 	// which. This will add the newly generated proto library to the appropriate attribute and nothing
@@ -925,13 +1020,25 @@
 	(&compilerAttrs).localIncludes.Append(rsLocalIncludes)
 	(&compilerAttrs).localIncludes.Value = android.FirstUniqueStrings(compilerAttrs.localIncludes.Value)
 
-	features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(bp2buildSanitizerFeatures(ctx, module))
+	sanitizerValues := bp2buildSanitizerFeatures(ctx, module)
+
+	features := compilerAttrs.features.Clone().Append(linkerAttrs.features).Append(sanitizerValues.features)
 	features = features.Append(bp2buildLtoFeatures(ctx, module))
 	features = features.Append(convertHiddenVisibilityToFeatureBase(ctx, module))
 	features.DeduplicateAxesFromBase()
 
+	compilerAttrs.copts = *compilerAttrs.copts.Append(sanitizerValues.copts)
+	compilerAttrs.additionalCompilerInputs = *compilerAttrs.additionalCompilerInputs.Append(sanitizerValues.additionalCompilerInputs)
+
 	addMuslSystemDynamicDeps(ctx, linkerAttrs)
 
+	// Dedupe all deps.
+	(&linkerAttrs).deps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).deps.Value)
+	(&linkerAttrs).implementationDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationDeps.Value)
+	(&linkerAttrs).implementationDynamicDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationDynamicDeps.Value)
+	(&linkerAttrs).wholeArchiveDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).wholeArchiveDeps.Value)
+	(&linkerAttrs).implementationWholeArchiveDeps.Value = bazel.FirstUniqueBazelLabelList((&linkerAttrs).implementationWholeArchiveDeps.Value)
+
 	return baseAttributes{
 		compilerAttrs,
 		linkerAttrs,
@@ -1273,10 +1380,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, 0, false)
+		SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, sharedDeps.implementation, &la.implementationDynamicDeps, 1, false)
 		if len(systemSharedLibs) > 0 {
-			setStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
+			SetStubsForDynamicDeps(ctx, axis, config, apexAvailable, bazelLabelForSharedDeps(ctx, systemSharedLibs), &la.systemDynamicDeps, 2, true)
 		}
 	}
 
@@ -1476,7 +1583,7 @@
 	}
 }
 
-func setStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
+func SetStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
 	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
 	// Create a config_setting for each apex_available.
@@ -1517,6 +1624,11 @@
 				if linkable, ok := ctx.Module().(LinkableInterface); ok && linkable.Bootstrap() {
 					sameApiDomain = true
 				}
+				// If dependency has `apex_available: ["//apex_available:platform]`, then the platform variant of rdep should link against its impl.
+				// https://cs.android.com/android/_/android/platform/build/soong/+/main:cc/cc.go;l=3617;bpv=1;bpt=0;drc=c6a93d853b37ec90786e745b8d282145e6d3b589
+				if depApexAvailable := dep.(*Module).ApexAvailable(); len(depApexAvailable) == 1 && depApexAvailable[0] == android.AvailableToPlatform {
+					sameApiDomain = true
+				}
 			} else {
 				sameApiDomain = android.InList(apiDomain, dep.(*Module).ApexAvailable())
 			}
@@ -1748,16 +1860,8 @@
 	return label
 }
 
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-cpp
-func xsdConfigCppTarget(ctx android.BazelConversionPathContext, mod blueprint.Module) string {
-	callback := func(xsd android.XsdConfigBp2buildTargets) string {
-		return xsd.CppBp2buildTargetName()
-	}
-	return android.XsdConfigBp2buildTarget(ctx, mod, callback)
-}
-
-func bazelLabelForXsdConfig(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, xsdConfigCppTarget)
+func xsdConfigCppTarget(xsd android.XsdConfigBp2buildTargets) string {
+	return xsd.CppBp2buildTargetName()
 }
 
 func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
@@ -1827,8 +1931,18 @@
 	return attrs
 }
 
-func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
+type sanitizerValues struct {
+	features                 bazel.StringListAttribute
+	copts                    bazel.StringListAttribute
+	additionalCompilerInputs bazel.LabelListAttribute
+}
+
+func bp2buildSanitizerFeatures(ctx android.BazelConversionPathContext, m *Module) sanitizerValues {
 	sanitizerFeatures := bazel.StringListAttribute{}
+	sanitizerCopts := bazel.StringListAttribute{}
+	sanitizerCompilerInputs := bazel.LabelListAttribute{}
+	memtagFeatures := bazel.StringListAttribute{}
+	memtagFeature := ""
 	bp2BuildPropParseHelper(ctx, m, &SanitizeProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		var features []string
 		if sanitizerProps, ok := props.(*SanitizeProperties); ok {
@@ -1840,9 +1954,10 @@
 			}
 			blocklist := sanitizerProps.Sanitize.Blocklist
 			if blocklist != nil {
-				// Format the blocklist name to be used in a feature name
-				blocklistFeatureSuffix := strings.Replace(strings.ToLower(*blocklist), ".", "_", -1)
-				features = append(features, "sanitizer_blocklist_"+blocklistFeatureSuffix)
+				// TODO: b/294868620 - Change this not to use the special axis when completing the bug
+				coptValue := fmt.Sprintf("-fsanitize-ignorelist=$(location %s)", *blocklist)
+				sanitizerCopts.SetSelectValue(bazel.SanitizersEnabledAxis, bazel.SanitizersEnabled, []string{coptValue})
+				sanitizerCompilerInputs.SetSelectValue(bazel.SanitizersEnabledAxis, bazel.SanitizersEnabled, bazel.MakeLabelListFromTargetNames([]string{*blocklist}))
 			}
 			if sanitizerProps.Sanitize.Cfi != nil && !proptools.Bool(sanitizerProps.Sanitize.Cfi) {
 				features = append(features, "-android_cfi")
@@ -1852,10 +1967,43 @@
 					features = append(features, "android_cfi_assembly_support")
 				}
 			}
+
+			if sanitizerProps.Sanitize.Memtag_heap != nil {
+				if (axis == bazel.NoConfigAxis && memtagFeature == "") ||
+					(axis == bazel.OsArchConfigurationAxis && config == bazel.OsArchAndroidArm64) {
+					memtagFeature = setMemtagValue(sanitizerProps, &memtagFeatures)
+				}
+			}
 			sanitizerFeatures.SetSelectValue(axis, config, features)
 		}
 	})
-	return sanitizerFeatures
+	sanitizerFeatures.Append(memtagFeatures)
+
+	return sanitizerValues{
+		features:                 sanitizerFeatures,
+		copts:                    sanitizerCopts,
+		additionalCompilerInputs: sanitizerCompilerInputs,
+	}
+}
+
+func setMemtagValue(sanitizerProps *SanitizeProperties, memtagFeatures *bazel.StringListAttribute) string {
+	var features []string
+	if proptools.Bool(sanitizerProps.Sanitize.Memtag_heap) {
+		features = append(features, "memtag_heap")
+	} else {
+		features = append(features, "-memtag_heap")
+	}
+	// Logic comes from: https://cs.android.com/android/platform/superproject/main/+/32ea1afbd1148b0b78553f24fa61116c999eb968:build/soong/cc/sanitize.go;l=910
+	if sanitizerProps.Sanitize.Diag.Memtag_heap != nil {
+		if proptools.Bool(sanitizerProps.Sanitize.Diag.Memtag_heap) {
+			features = append(features, "diag_memtag_heap")
+		} else {
+			features = append(features, "-diag_memtag_heap")
+		}
+	}
+	memtagFeatures.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, features)
+
+	return features[0]
 }
 
 func bp2buildLtoFeatures(ctx android.BazelConversionPathContext, m *Module) bazel.StringListAttribute {
diff --git a/cc/cc.go b/cc/cc.go
index be67286..3b92696 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -74,6 +74,9 @@
 		ctx.TopDown("afdo_deps", afdoDepsMutator)
 		ctx.BottomUp("afdo", afdoMutator).Parallel()
 
+		ctx.TopDown("orderfile_deps", orderfileDepsMutator)
+		ctx.BottomUp("orderfile", orderfileMutator).Parallel()
+
 		ctx.TopDown("lto_deps", ltoDepsMutator)
 		ctx.BottomUp("lto", ltoMutator).Parallel()
 
@@ -526,6 +529,7 @@
 	getVndkExtendsModuleName() string
 	isAfdoCompile() bool
 	isPgoCompile() bool
+	isOrderfileCompile() bool
 	isCfi() bool
 	isFuzzer() bool
 	isNDKStubLibrary() bool
@@ -885,6 +889,7 @@
 	lto      *lto
 	afdo     *afdo
 	pgo      *pgo
+	orderfile *orderfile
 
 	library libraryInterface
 
@@ -1259,6 +1264,9 @@
 	if c.pgo != nil {
 		c.AddProperties(c.pgo.props()...)
 	}
+	if c.orderfile != nil {
+		c.AddProperties(c.orderfile.props()...)
+	}
 	for _, feature := range c.features {
 		c.AddProperties(feature.props()...)
 	}
@@ -1392,6 +1400,13 @@
 	return false
 }
 
+func (c *Module) isOrderfileCompile() bool {
+	if orderfile := c.orderfile; orderfile != nil {
+		return orderfile.Properties.OrderfileLoad
+	}
+	return false
+}
+
 func (c *Module) isCfi() bool {
 	if sanitize := c.sanitize; sanitize != nil {
 		return Bool(sanitize.Properties.SanitizeMutated.Cfi)
@@ -1697,6 +1712,10 @@
 	return ctx.mod.isPgoCompile()
 }
 
+func (ctx *moduleContextImpl) isOrderfileCompile() bool {
+	return ctx.mod.isOrderfileCompile()
+}
+
 func (ctx *moduleContextImpl) isCfi() bool {
 	return ctx.mod.isCfi()
 }
@@ -1806,6 +1825,7 @@
 	module.lto = &lto{}
 	module.afdo = &afdo{}
 	module.pgo = &pgo{}
+	module.orderfile = &orderfile{}
 	return module
 }
 
@@ -2234,6 +2254,9 @@
 	if c.pgo != nil {
 		flags = c.pgo.flags(ctx, flags)
 	}
+	if c.orderfile != nil {
+		flags = c.orderfile.flags(ctx, flags)
+	}
 	for _, feature := range c.features {
 		flags = feature.flags(ctx, flags)
 	}
@@ -2376,6 +2399,9 @@
 	if c.lto != nil {
 		c.lto.begin(ctx)
 	}
+	if c.orderfile != nil {
+		c.orderfile.begin(ctx)
+	}
 	if c.pgo != nil {
 		c.pgo.begin(ctx)
 	}
@@ -4284,6 +4310,7 @@
 		&LTOProperties{},
 		&AfdoProperties{},
 		&PgoProperties{},
+		&OrderfileProperties{},
 		&android.ProtoProperties{},
 		// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
 		&RustBindgenClangProperties{},
diff --git a/cc/cc_test.go b/cc/cc_test.go
index d95ed3f..7ce0f37 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -654,6 +654,7 @@
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
+	config.TestProductVariables.KeepVndk = BoolPtr(true)
 	ctx := testCcWithConfig(t, config)
 
 	module := ctx.ModuleForTests("llndk.libraries.txt", "android_common")
diff --git a/cc/compiler.go b/cc/compiler.go
index 16f4a6e..5bed8a7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -189,13 +189,13 @@
 			// build the recovery variant of the C/C++ module.
 			Exclude_generated_sources []string
 		}
-		Vendor_ramdisk struct {
+		Ramdisk, Vendor_ramdisk struct {
 			// list of source files that should not be used to
-			// build the vendor ramdisk variant of the C/C++ module.
+			// build the ramdisk variants of the C/C++ module.
 			Exclude_srcs []string `android:"path"`
 
-			// List of additional cflags that should be used to build the vendor ramdisk
-			// variant of the C/C++ module.
+			// List of additional cflags that should be used to build the ramdisk
+			// variants of the C/C++ module.
 			Cflags []string
 		}
 		Platform struct {
@@ -351,6 +351,7 @@
 	CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
 	CheckBadCompilerFlags(ctx, "product.cflags", compiler.Properties.Target.Product.Cflags)
 	CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
+	CheckBadCompilerFlags(ctx, "ramdisk.cflags", compiler.Properties.Target.Ramdisk.Cflags)
 	CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags)
 	CheckBadCompilerFlags(ctx, "platform.cflags", compiler.Properties.Target.Platform.Cflags)
 
@@ -536,6 +537,9 @@
 	if ctx.inVendorRamdisk() {
 		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...)
 	}
+	if ctx.inRamdisk() {
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Ramdisk.Cflags)...)
+	}
 	if !ctx.useSdk() {
 		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Platform.Cflags)...)
 	}
diff --git a/cc/config/OWNERS b/cc/config/OWNERS
index 580f215..c78b6d5 100644
--- a/cc/config/OWNERS
+++ b/cc/config/OWNERS
@@ -1,3 +1,3 @@
 per-file vndk.go = smoreland@google.com, victoryang@google.com
-per-file clang.go,global.go,tidy.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
+per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com
 
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index ca2e05f..12722a7 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -100,7 +100,15 @@
 		return strings.Join(flags, " ")
 	})
 
-	exportedVars.ExportStringListStaticVariable("Arm64Cflags", arm64Cflags)
+	exportedVars.ExportStringList("Arm64Cflags", arm64Cflags)
+	pctx.VariableFunc("Arm64Cflags", func(ctx android.PackageVarContext) string {
+		flags := arm64Cflags
+		if ctx.Config().PageSizeAgnostic() {
+			flags = append(flags, "-D__BIONIC_NO_PAGE_SIZE_MACRO")
+		}
+		return strings.Join(flags, " ")
+	})
+
 	exportedVars.ExportStringListStaticVariable("Arm64Cppflags", arm64Cppflags)
 
 	exportedVars.ExportVariableReferenceDict("Arm64ArchVariantCflags", arm64ArchVariantCflagsVar)
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 3397e3d..3d6890c 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -183,12 +183,7 @@
 	exportedVars.ExportString("ArmClangTriple", clangTriple)
 
 	exportedVars.ExportStringListStaticVariable("ArmLdflags", armLdflags)
-	exportedVars.ExportStringList("ArmLldflags", armLldflags)
-	pctx.VariableFunc("ArmLldflags", func(ctx android.PackageVarContext) string {
-		maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported()
-		flags := append(armLldflags, maxPageSizeFlag)
-		return strings.Join(flags, " ")
-	})
+	exportedVars.ExportStringListStaticVariable("ArmLldflags", armLldflags)
 
 	exportedVars.ExportStringListStaticVariable("ArmFixCortexA8LdFlags", armFixCortexA8LdFlags)
 	exportedVars.ExportStringListStaticVariable("ArmNoFixCortexA8LdFlags", armNoFixCortexA8LdFlags)
diff --git a/cc/config/global.go b/cc/config/global.go
index 266d278..174b12c 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -45,7 +45,6 @@
 		"-UDEBUG",
 
 		"-fno-exceptions",
-		"-Wno-multichar",
 
 		"-O2",
 		"-fdebug-default-version=5",
@@ -75,32 +74,30 @@
 		// Help catch common 32/64-bit errors.
 		"-Werror=int-conversion",
 
-		// Disable overly aggressive warning for macros defined with a leading underscore
-		// This happens in AndroidConfig.h, which is included nearly everywhere.
-		// TODO: can we remove this now?
-		"-Wno-reserved-id-macro",
-
 		// Force clang to always output color diagnostics. Ninja will strip the ANSI
 		// color codes if it is not running in a terminal.
 		"-fcolor-diagnostics",
 
-		// Warnings from clang-7.0
+		// -Wno-sign-compare 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",
 
-		// Disable -Winconsistent-missing-override until we can clean up the existing
-		// codebase for it.
+		// 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",
 
-		// Warnings from clang-10
-		// Nested and array designated initialization is nice to have.
+		// Designated initializer syntax is recommended by the Google C++ style
+		// guide and should not be a warning, at least by default.
 		"-Wno-c99-designator",
 
-		// Many old files still have GNU designator syntax.
-		"-Wno-gnu-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",
@@ -142,6 +139,9 @@
 		"-Werror=format-security",
 		"-nostdlibinc",
 
+		// Enable MLGO for register allocation.
+		"-mllvm -regalloc-enable-advisor=release",
+
 		// Emit additional debug info for AutoFDO
 		"-fdebug-info-for-profiling",
 	}
@@ -149,6 +149,7 @@
 	commonGlobalLldflags = []string{
 		"-fuse-ld=lld",
 		"-Wl,--icf=safe",
+		"-Wl,--no-demangle",
 	}
 
 	deviceGlobalCppflags = []string{
@@ -168,6 +169,8 @@
 		"-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...)
@@ -193,6 +196,8 @@
 		"-Wno-gnu-include-next",
 	}
 
+	// These flags are appended after the module's cflags, so they cannot be
+	// overridden from Android.bp files.
 	noOverrideGlobalCflags = []string{
 		"-Werror=bool-operation",
 		"-Werror=format-insufficient-args",
@@ -217,8 +222,6 @@
 		// new warnings are fixed.
 		"-Wno-tautological-constant-compare",
 		"-Wno-tautological-type-limit-compare",
-		// http://b/145210666
-		"-Wno-reorder-init-list",
 		// http://b/145211066
 		"-Wno-implicit-int-float-conversion",
 		// New warnings to be fixed after clang-r377782.
@@ -246,16 +249,27 @@
 
 	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/191699019
 		"-Wno-format-insufficient-args",
-		"-Wno-sizeof-array-div",
+		// 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-bitwise-instead-of-logical",
-		"-Wno-misleading-indentation",
 		"-Wno-array-parameter",
 		"-Wno-gnu-offsetof-extensions",
 	}
@@ -307,7 +321,7 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r498229"
+	ClangDefaultVersion      = "clang-r498229b"
 	ClangDefaultShortVersion = "17"
 
 	// Directories with warnings from Android.bp files.
diff --git a/cc/coverage.go b/cc/coverage.go
index c0f6973..cbd8a6f 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -48,6 +48,7 @@
 func getGcovProfileLibraryName(ctx ModuleContextIntf) string {
 	// This function should only ever be called for a cc.Module, so the
 	// following statement should always succeed.
+	// LINT.IfChange
 	if ctx.useSdk() {
 		return "libprofile-extras_ndk"
 	} else {
@@ -63,6 +64,7 @@
 	} else {
 		return "libprofile-clang-extras"
 	}
+	// LINT.ThenChange(library.go)
 }
 
 func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
diff --git a/cc/image.go b/cc/image.go
index e65a9aa..f91762a 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -678,10 +678,17 @@
 	}
 }
 
+func squashRamdiskSrcs(m *Module) {
+	if lib, ok := m.compiler.(*libraryDecorator); ok {
+		lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Ramdisk.Exclude_srcs...)
+	}
+}
+
 func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 	m := module.(*Module)
 	if variant == android.RamdiskVariation {
 		m.MakeAsPlatform()
+		squashRamdiskSrcs(m)
 	} else if variant == android.VendorRamdiskVariation {
 		m.MakeAsPlatform()
 		squashVendorRamdiskSrcs(m)
diff --git a/cc/library.go b/cc/library.go
index 266fa75..2d4d604 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -32,6 +32,20 @@
 	"github.com/google/blueprint/proptools"
 )
 
+var (
+	alwaysLinkLibraries = map[string]bool{
+		// Coverage libraries are _always_ added as a whole_static_dep. By converting as these as
+		// alwayslink = True, we can add these as to deps (e.g. as a regular static dep) in Bazel
+		// without any extra complications in cc_shared_library roots to prevent linking the same
+		// library repeatedly.
+		"libprofile-extras_ndk":               true,
+		"libprofile-extras":                   true,
+		"libprofile-clang-extras_ndk":         true,
+		"libprofile-clang-extras_cfi_support": true,
+		"libprofile-clang-extras":             true,
+	}
+)
+
 // LibraryProperties is a collection of properties shared by cc library rules/cc.
 type LibraryProperties struct {
 	// local file name to pass to the linker as -unexported_symbols_list
@@ -335,6 +349,7 @@
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
 		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
 		Native_coverage:                   baseAttributes.Native_coverage,
+		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
 	}
 
 	includeAttrs := includesAttributes{
@@ -362,6 +377,7 @@
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
 		sdkAttributes:                     bp2BuildParseSdkAttributes(m),
 		Native_coverage:                   baseAttributes.Native_coverage,
+		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
 	}
 
 	staticTargetAttrs := &bazelCcLibraryStaticAttributes{
@@ -435,6 +451,10 @@
 		Bzl_load_location: "//build/bazel/rules/cc:cc_library_shared.bzl",
 	}
 
+	if _, ok := alwaysLinkLibraries[m.Name()]; ok {
+		staticTargetAttrs.Alwayslink = proptools.BoolPtr(true)
+	}
+
 	var tagsForStaticVariant bazel.StringListAttribute
 	if compilerAttrs.stubsSymbolFile == nil && len(compilerAttrs.stubsVersions.Value) == 0 {
 		tagsForStaticVariant = android.ApexAvailableTagsWithoutTestApexes(ctx, m)
@@ -2944,6 +2964,7 @@
 		sdkAttributes:                     bp2BuildParseSdkAttributes(module),
 		Runtime_deps:                      linkerAttrs.runtimeDeps,
 		Native_coverage:                   baseAttributes.Native_coverage,
+		Additional_compiler_inputs:        compilerAttrs.additionalCompilerInputs,
 	}
 
 	module.convertTidyAttributes(ctx, &commonAttrs.tidyAttributes)
@@ -2951,6 +2972,10 @@
 	var attrs interface{}
 	if isStatic {
 		commonAttrs.Deps.Add(baseAttributes.protoDependency)
+		var alwayslink *bool
+		if _, ok := alwaysLinkLibraries[module.Name()]; ok && isStatic {
+			alwayslink = proptools.BoolPtr(true)
+		}
 		attrs = &bazelCcLibraryStaticAttributes{
 			staticOrSharedAttributes: commonAttrs,
 			Rtti:                     compilerAttrs.rtti,
@@ -2964,8 +2989,10 @@
 			Conlyflags: compilerAttrs.conlyFlags,
 			Asflags:    asFlags,
 
-			Features: *features,
+			Alwayslink: alwayslink,
+			Features:   *features,
 		}
+
 	} else {
 		commonAttrs.Dynamic_deps.Add(baseAttributes.protoDependency)
 
@@ -3047,7 +3074,8 @@
 	Conlyflags bazel.StringListAttribute
 	Asflags    bazel.StringListAttribute
 
-	Features bazel.StringListAttribute
+	Alwayslink *bool
+	Features   bazel.StringListAttribute
 }
 
 // TODO(b/199902614): Can this be factored to share with the other Attributes?
diff --git a/cc/linkable.go b/cc/linkable.go
index 2099399..5b5b856 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -95,6 +95,18 @@
 
 	// IsSnapshotPrebuilt returns true if this module is a snapshot prebuilt.
 	IsSnapshotPrebuilt() bool
+
+	// IsSnapshotSanitizer returns true if this snapshot module implements SnapshotSanitizer.
+	IsSnapshotSanitizer() bool
+
+	// IsSnapshotSanitizerAvailable returns true if this snapshot module has a sanitizer source available (cfi, hwasan).
+	IsSnapshotSanitizerAvailable(t SanitizerType) bool
+
+	// SetSnapshotSanitizerVariation sets the sanitizer variation type for this snapshot module.
+	SetSnapshotSanitizerVariation(t SanitizerType, enabled bool)
+
+	// IsSnapshotUnsanitizedVariant returns true if this is the unsanitized snapshot module variant.
+	IsSnapshotUnsanitizedVariant() bool
 }
 
 // LinkableInterface is an interface for a type of module that is linkable in a C++ library.
diff --git a/cc/lto.go b/cc/lto.go
index 44361db..df9ca0a 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -135,10 +135,14 @@
 			ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
 		}
 
-		// If the module does not have a profile, be conservative and limit cross TU inline
-		// limit to 5 LLVM IR instructions, to balance binary size increase and performance.
-		if !ctx.Darwin() && !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
-			ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
+		// Reduce the inlining threshold for a better balance of binary size and
+		// performance.
+		if !ctx.Darwin() {
+			if ctx.isPgoCompile() || ctx.isAfdoCompile() {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
+			} else {
+				ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
+			}
 		}
 
 		flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f0b7cc5..9281aeb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -31,9 +31,8 @@
 
 func init() {
 	pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
-	pctx.HostBinToolVariable("abidiff", "abidiff")
-	pctx.HostBinToolVariable("abitidy", "abitidy")
-	pctx.HostBinToolVariable("abidw", "abidw")
+	pctx.HostBinToolVariable("stg", "stg")
+	pctx.HostBinToolVariable("stgdiff", "stgdiff")
 }
 
 var (
@@ -44,28 +43,20 @@
 			CommandDeps: []string{"$ndkStubGenerator"},
 		}, "arch", "apiLevel", "apiMap", "flags")
 
-	abidw = pctx.AndroidStaticRule("abidw",
+	stg = pctx.AndroidStaticRule("stg",
 		blueprint.RuleParams{
-			Command: "$abidw --type-id-style hash --no-corpus-path " +
-				"--no-show-locs --no-comp-dir-path -w $symbolList " +
-				"$in --out-file $out",
-			CommandDeps: []string{"$abidw"},
+			Command:     "$stg -S :$symbolList --elf $in -o $out",
+			CommandDeps: []string{"$stg"},
 		}, "symbolList")
 
-	abitidy = pctx.AndroidStaticRule("abitidy",
-		blueprint.RuleParams{
-			Command:     "$abitidy --all $flags -i $in -o $out",
-			CommandDeps: []string{"$abitidy"},
-		}, "flags")
-
-	abidiff = pctx.AndroidStaticRule("abidiff",
+	stgdiff = pctx.AndroidStaticRule("stgdiff",
 		blueprint.RuleParams{
 			// Need to create *some* output for ninja. We don't want to use tee
 			// because we don't want to spam the build output with "nothing
 			// changed" messages, so redirect output message to $out, and if
 			// changes were detected print the output and fail.
-			Command:     "$abidiff $args $in > $out || (cat $out && false)",
-			CommandDeps: []string{"$abidiff"},
+			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+			CommandDeps: []string{"$stgdiff"},
 		}, "args")
 
 	ndkLibrarySuffix = ".ndk"
@@ -107,12 +98,6 @@
 	// https://github.com/android-ndk/ndk/issues/265.
 	Unversioned_until *string
 
-	// If true, does not emit errors when APIs lacking type information are
-	// found. This is false by default and should not be enabled outside bionic,
-	// where it is enabled pending a fix for http://b/190554910 (no debug info
-	// for asm implemented symbols).
-	Allow_untyped_symbols *bool
-
 	// Headers presented by this library to the Public API Surface
 	Export_header_libs []string
 }
@@ -326,7 +311,7 @@
 	apiLevel android.ApiLevel) android.OptionalPath {
 
 	subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(),
-		ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml")
+		ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg")
 	return android.ExistentPathForSource(ctx, subpath)
 }
 
@@ -359,34 +344,17 @@
 
 func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
 	implementationLibrary := this.findImplementationLibrary(ctx)
-	abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx,
-		this.apiLevel.String(), ctx.Arch().ArchType.String(),
-		this.libraryName(ctx), "abi.raw.xml")
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        abidw,
-		Description: fmt.Sprintf("abidw %s", implementationLibrary),
-		Input:       implementationLibrary,
-		Output:      abiRawPath,
-		Implicit:    symbolList,
-		Args: map[string]string{
-			"symbolList": symbolList.String(),
-		},
-	})
-
 	this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
 		this.apiLevel.String(), ctx.Arch().ArchType.String(),
-		this.libraryName(ctx), "abi.xml")
-	untypedFlag := "--abort-on-untyped-symbols"
-	if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) {
-		untypedFlag = ""
-	}
+		this.libraryName(ctx), "abi.stg")
 	ctx.Build(pctx, android.BuildParams{
-		Rule:        abitidy,
-		Description: fmt.Sprintf("abitidy %s", implementationLibrary),
-		Input:       abiRawPath,
+		Rule:        stg,
+		Description: fmt.Sprintf("stg %s", implementationLibrary),
+		Input:       implementationLibrary,
+		Implicit:    symbolList,
 		Output:      this.abiDumpPath,
 		Args: map[string]string{
-			"flags": untypedFlag,
+			"symbolList": symbolList.String(),
 		},
 	})
 }
@@ -405,7 +373,7 @@
 func (this *stubDecorator) diffAbi(ctx ModuleContext) {
 	// Catch any ABI changes compared to the checked-in definition of this API
 	// level.
-	abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp")
+	abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
 	prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
 	missingPrebuiltError := fmt.Sprintf(
 		"Did not find prebuilt ABI dump for %q (%q). Generate with "+
@@ -421,11 +389,14 @@
 		})
 	} else {
 		ctx.Build(pctx, android.BuildParams{
-			Rule: abidiff,
-			Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump,
+			Rule: stgdiff,
+			Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump,
 				this.abiDumpPath),
 			Output: abiDiffPath,
 			Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath},
+			Args: map[string]string{
+				"args": "--format=small",
+			},
 		})
 	}
 	this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath)
@@ -452,13 +423,13 @@
 			})
 		} else {
 			ctx.Build(pctx, android.BuildParams{
-				Rule: abidiff,
+				Rule: stgdiff,
 				Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath,
 					nextAbiDump),
 				Output: nextAbiDiffPath,
 				Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()},
 				Args: map[string]string{
-					"args": "--no-added-syms",
+					"args": "--format=small --ignore=interface_addition",
 				},
 			})
 		}
diff --git a/cc/orderfile.go b/cc/orderfile.go
new file mode 100644
index 0000000..b64c1c7
--- /dev/null
+++ b/cc/orderfile.go
@@ -0,0 +1,256 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Note: If you want to know how to use orderfile for your binary or shared
+// library, you can go look at the README in toolchains/pgo-profiles/orderfiles
+
+package cc
+
+import (
+	"fmt"
+
+	"android/soong/android"
+)
+
+// Order files are text files containing symbols representing functions names.
+// Linkers (lld) uses order files to layout functions in a specific order.
+// These binaries with ordered symbols will reduce page faults and improve a program's launch time
+// due to the efficient loading of symbols during a program’s cold-start.
+var (
+	// Add flags to ignore warnings about symbols not be found
+	// or not allowed to be ordered
+	orderfileOtherFlags = []string{
+		"-Wl,--no-warn-symbol-ordering",
+	}
+
+	// Add folder projects for orderfiles
+	globalOrderfileProjects = []string{
+		"toolchain/pgo-profiles/orderfiles",
+		"vendor/google_data/pgo_profile/orderfiles",
+	}
+)
+
+var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
+
+const orderfileProfileFlag = "-forder-file-instrumentation"
+const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
+
+func getOrderfileProjects(config android.DeviceConfig) []string {
+	return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
+		return globalOrderfileProjects
+	})
+}
+
+func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
+	getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
+}
+
+type OrderfileProperties struct {
+	Orderfile struct {
+		Instrumentation    *bool
+		Order_file_path    *string `android:"arch_variant"`
+		Load_order_file    *bool `android:"arch_variant"`
+		// Additional compiler flags to use when building this module
+		// for orderfile profiling.
+		Cflags []string `android:"arch_variant"`
+	} `android:"arch_variant"`
+
+	ShouldProfileModule 	  bool `blueprint:"mutated"`
+	OrderfileLoad             bool `blueprint:"mutated"`
+	OrderfileInstrLink        bool `blueprint:"mutated"`
+}
+
+type orderfile struct {
+	Properties OrderfileProperties
+}
+
+func (props *OrderfileProperties) shouldInstrument() bool {
+	return Bool(props.Orderfile.Instrumentation)
+}
+
+// ShouldLoadOrderfile returns true if we need to load the order file rather than
+// profile the binary or shared library
+func (props *OrderfileProperties) shouldLoadOrderfile() bool {
+	return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
+}
+
+// orderfileEnabled returns true for binaries and shared libraries
+// if instrument flag is set to true
+func (orderfile *orderfile) orderfileEnabled() bool {
+	return orderfile != nil && orderfile.Properties.shouldInstrument()
+}
+
+// orderfileLinkEnabled returns true for binaries and shared libraries
+// if you should instrument dependencies
+func (orderfile *orderfile) orderfileLinkEnabled() bool {
+	return orderfile != nil && orderfile.Properties.OrderfileInstrLink
+}
+
+func (orderfile *orderfile) props() []interface{} {
+	return []interface{}{&orderfile.Properties}
+}
+
+// Get the path to the order file by checking it is valid and not empty
+func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
+	orderFile := *props.Orderfile.Order_file_path
+
+	// Test if the order file is present in any of the Orderfile projects
+	for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
+		path := android.ExistentPathForSource(ctx, profileProject, orderFile)
+		if path.Valid() {
+			return path
+		}
+	}
+
+	// Record that this module's order file is absent
+	missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+	recordMissingOrderfile(ctx, missing)
+
+	return android.OptionalPath{}
+}
+
+func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+	flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
+	flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
+	flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
+	flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
+	return flags
+}
+
+
+func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
+	flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
+	flags = append(flags, orderfileOtherFlags...)
+	return flags
+}
+
+func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
+	orderFile := props.getOrderfile(ctx)
+	orderFilePath := orderFile.Path()
+	loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
+
+	flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
+
+	// Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+	// if orderfile gets updated
+	flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
+	flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
+	return flags
+}
+
+func (orderfile *orderfile) begin(ctx BaseModuleContext) {
+	// Currently, we are not enabling orderfiles for host
+	if ctx.Host() {
+		return
+	}
+
+	// Currently, we are not enabling orderfiles to begin from static libraries
+	if ctx.static() && !ctx.staticBinary() {
+		return
+	}
+
+	if ctx.DeviceConfig().ClangCoverageEnabled() {
+		return
+	}
+
+	// Checking if orderfile is enabled for this module
+	if !orderfile.orderfileEnabled() {
+		return
+	}
+
+	orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
+	orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
+	orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
+}
+
+func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
+	props := orderfile.Properties
+	// Add flags to load the orderfile using the path in its Android.bp
+	if orderfile.Properties.OrderfileLoad {
+		flags = props.addLoadFlags(ctx, flags)
+		return flags
+	}
+
+	// Add flags to profile this module
+	if props.ShouldProfileModule {
+		flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
+		return flags
+	}
+
+	return flags
+}
+
+// Propagate profile orderfile flags down from binaries and shared libraries
+// We do not allow propagation for load flags because the orderfile is specific
+// to the module (binary / shared library)
+func orderfileDepsMutator(mctx android.TopDownMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok {
+		if !m.orderfile.orderfileLinkEnabled() {
+			return
+		}
+		mctx.WalkDeps(func(dep android.
+			Module, parent android.Module) bool {
+			tag := mctx.OtherModuleDependencyTag(dep)
+			libTag, isLibTag := tag.(libraryDependencyTag)
+
+			// Do not recurse down non-static dependencies
+			if isLibTag {
+				if !libTag.static() {
+					return false
+				}
+			} else {
+				if tag != objDepTag && tag != reuseObjTag {
+					return false
+				}
+			}
+
+			if dep, ok := dep.(*Module); ok {
+				if m.orderfile.Properties.OrderfileInstrLink {
+					dep.orderfile.Properties.OrderfileInstrLink = true;
+				}
+			}
+
+			return true
+		})
+	}
+}
+
+// Create orderfile variants for modules that need them
+func orderfileMutator(mctx android.BottomUpMutatorContext) {
+	if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil {
+		if !m.static() && m.orderfile.orderfileEnabled() {
+			mctx.SetDependencyVariation("orderfile")
+			return
+		}
+
+		variationNames := []string{""}
+		if m.orderfile.Properties.OrderfileInstrLink {
+			variationNames = append(variationNames, "orderfile")
+		}
+
+		if len(variationNames) > 1 {
+			modules := mctx.CreateVariations(variationNames...)
+			for i, name := range variationNames {
+				if name == "" {
+					continue
+				}
+				variation := modules[i].(*Module)
+				variation.Properties.PreventInstall = true
+				variation.Properties.HideFromMake = true
+				variation.orderfile.Properties.ShouldProfileModule = true
+				variation.orderfile.Properties.OrderfileLoad = false
+			}
+		}
+	}
+}
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
new file mode 100644
index 0000000..f68457d
--- /dev/null
+++ b/cc/orderfile_test.go
@@ -0,0 +1,470 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+	"testing"
+	"strings"
+
+	"android/soong/android"
+)
+
+func TestOrderfileProfileSharedLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	// Check cFlags of orderfile-enabled module
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check ldFlags of orderfile-enabled module
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+func TestOrderfileLoadSharedLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "libTest.orderfile",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/libTest.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile"
+
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	// Check ldFlags of orderfile-enabled module
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+func TestOrderfileProfileBinary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_binary {
+		name: "test",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	test := result.ModuleForTests("test", "android_arm64_armv8-a")
+
+	// Check cFlags of orderfile-enabled module
+	cFlags := test.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'test' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check ldFlags of orderfile-enabled module
+	ldFlags := test.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'test' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+func TestOrderfileLoadBinary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_binary {
+		name: "test",
+		srcs: ["test.c"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "test.orderfile",
+		},
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+	test := result.ModuleForTests("test", "android_arm64_armv8-a")
+
+	// Check ldFlags of orderfile-enabled module
+	ldFlags := test.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'test' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+	}
+}
+
+// Profile flags should propagate through static libraries
+func TestOrderfileProfilePropagateStaticDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags of orderfile-enabled module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check cFlags of orderfile variant static libraries
+	libFooOfVariant  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
+	libBarOfVariant  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
+
+	cFlags = libFooOfVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFooOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBarOfVariant.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBarOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to orderfile variant static libraries
+	if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) {
+		t.Errorf("libTest missing dependency on orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) {
+		t.Errorf("libTest missing dependency on orderfile variant of libBar")
+	}
+
+	// Check cFlags of the non-orderfile variant static libraries
+	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+	cFlags = libFoo.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBar.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+	if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest has dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest has dependency on non-orderfile variant of libBar")
+	}
+}
+
+// Load flags should never propagate
+func TestOrderfileLoadPropagateStaticDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: true,
+			order_file_path: "test.orderfile",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+		android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+	// Check ldFlags of orderfile-enabled module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldFlags %q", expectedCFlag, ldFlags)
+	}
+
+	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+	// Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for static libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
+
+// Profile flags should not propagate through shared libraries
+func TestOrderfileProfilePropagateSharedDeps(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_shared {
+		name: "libTest",
+		srcs: ["test.c"],
+		shared_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_shared {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags of orderfile-enabled module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if !strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check cFlags of the static and shared libraries
+	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
+	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+	cFlags = libFoo.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBar.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
+
+// Profile flags should not work or be propagated if orderfile flags start at a static library
+func TestOrderfileProfileStaticLibrary(t *testing.T) {
+	t.Parallel()
+	bp := `
+	cc_library_static {
+		name: "libTest",
+		srcs: ["test.c"],
+		static_libs: ["libFoo"],
+		orderfile : {
+			instrumentation: true,
+			load_order_file: false,
+			order_file_path: "",
+		},
+	}
+
+	cc_library_static {
+		name: "libFoo",
+		srcs: ["foo.c"],
+		static_libs: ["libBar"],
+	}
+
+	cc_library_static {
+		name: "libBar",
+		srcs: ["bar.c"],
+	}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForCcTest,
+	).RunTestWithBp(t, bp)
+
+	expectedCFlag := "-forder-file-instrumentation"
+
+	// Check cFlags of module
+	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static")
+
+	cFlags := libTest.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libTest' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check cFlags of the static libraries
+	libFoo  := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+	libBar  := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+	cFlags = libFoo.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	cFlags = libBar.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, expectedCFlag) {
+		t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+	}
+
+	// Check dependency edge from orderfile-enabled module to non-orderfile variant libraries
+	if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+		t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+	}
+
+	// Make sure no orderfile variants are created for static libraries because the flags were not propagated
+	libFooVariants := result.ModuleVariantsForTests("libFoo")
+	for _, v := range libFooVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+		}
+	}
+
+	libBarVariants := result.ModuleVariantsForTests("libBar")
+	for _, v := range libBarVariants {
+		if strings.Contains(v, "orderfile") {
+			t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+		}
+	}
+}
\ No newline at end of file
diff --git a/cc/proto.go b/cc/proto.go
index 5d9aef6..0ed4381 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -165,7 +165,17 @@
 }
 
 type protoAttributes struct {
-	Deps            bazel.LabelListAttribute
+	Deps bazel.LabelListAttribute
+
+	// A list of proto_library targets that that the proto_library in `deps` depends on
+	// This list is overestimation.
+	// Overestimation is necessary since Soong includes other protos via proto.include_dirs and not
+	// a specific .proto file module explicitly.
+	Transitive_deps bazel.LabelListAttribute
+
+	// A list of cc_library_* targets that the generated cpp code depends on
+	Cc_deps bazel.LabelListAttribute
+
 	Min_sdk_version *string
 }
 
@@ -175,7 +185,7 @@
 	protoDep                     *bazel.LabelAttribute
 }
 
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) bp2buildProtoDeps {
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute, la linkerAttributes) bp2buildProtoDeps {
 	var ret bp2buildProtoDeps
 
 	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
@@ -204,6 +214,35 @@
 
 	var protoAttrs protoAttributes
 	protoAttrs.Deps.SetValue(protoInfo.Proto_libs)
+	protoAttrs.Transitive_deps.SetValue(protoInfo.Transitive_proto_libs)
+
+	// Add the implementation deps of the top-level cc_library_static
+	// This is necessary to compile the internal root of cc_proto_library.
+	// Without this, clang might not be able to find .h files that the generated cpp files depends on
+	protoAttrs.Cc_deps = *la.implementationDeps.Clone()
+	protoAttrs.Cc_deps.Append(la.implementationDynamicDeps)
+	protoAttrs.Cc_deps.Append(la.implementationWholeArchiveDeps)
+	protoAttrs.Cc_deps.Append(la.wholeArchiveDeps)
+	// Subtract myself to prevent possible circular dep
+	protoAttrs.Cc_deps = bazel.SubtractBazelLabelListAttribute(
+		protoAttrs.Cc_deps,
+		bazel.MakeLabelListAttribute(
+			bazel.MakeLabelList([]bazel.Label{
+				bazel.Label{Label: ":" + m.Name() + suffix},
+			}),
+		),
+	)
+	// Subtract the protobuf libraries since cc_proto_library implicitly adds them
+	protoAttrs.Cc_deps = bazel.SubtractBazelLabelListAttribute(
+		protoAttrs.Cc_deps,
+		bazel.MakeLabelListAttribute(
+			bazel.MakeLabelList([]bazel.Label{
+				bazel.Label{Label: "//external/protobuf:libprotobuf-cpp-full", OriginalModuleName: "libprotobuf-cpp-full"},
+				bazel.Label{Label: "//external/protobuf:libprotobuf-cpp-lite", OriginalModuleName: "libprotobuf-cpp-lite"},
+			}),
+		),
+	)
+
 	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
 
 	name := m.Name() + suffix
diff --git a/cc/rs.go b/cc/rs.go
index 6507259..93acdc7 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -101,11 +101,12 @@
 func rsFlags(ctx ModuleContext, flags Flags, properties *BaseCompilerProperties) Flags {
 	targetApi := String(properties.Renderscript.Target_api)
 	if targetApi == "" && ctx.useSdk() {
-		switch ctx.sdkVersion() {
-		case "current", "system_current", "test_current":
-			// Nothing
-		default:
-			targetApi = android.GetNumericSdkVersion(ctx.sdkVersion())
+		targetApiLevel := android.ApiLevelOrPanic(ctx, ctx.sdkVersion())
+		if targetApiLevel.IsCurrent() || targetApiLevel.IsPreview() {
+			// If the target level is current or preview, leave the 'target-api' unset.
+			// This signals to llvm-rs-cc that the development API should be used.
+		} else {
+			targetApi = targetApiLevel.String()
 		}
 	}
 
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 626005b..0abdafc 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -56,10 +56,6 @@
 		// higher number of "optimized out" stack variables.
 		// b/112437883.
 		"-instcombine-lower-dbg-declare=0",
-		// TODO(b/159343917): HWASan and GlobalISel don't play nicely, and
-		// GlobalISel is the default at -O0 on aarch64.
-		"--aarch64-enable-global-isel-at-O=-1",
-		"-fast-isel=false",
 		"-hwasan-use-after-scope=1",
 		"-dom-tree-reachability-max-bbs-to-explore=128",
 	}
@@ -91,6 +87,8 @@
 
 	hostOnlySanitizeFlags   = []string{"-fno-sanitize-recover=all"}
 	deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"}
+
+	noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime"
 )
 
 type SanitizerType int
@@ -411,6 +409,8 @@
 	exportedVars.ExportStringListStaticVariable("HostOnlySanitizeFlags", hostOnlySanitizeFlags)
 	exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags)
 
+	exportedVars.ExportStringList("MinimalRuntimeFlags", minimalRuntimeFlags)
+
 	// Leave out "-flto" from the slices exported to bazel, as we will use the
 	// dedicated LTO feature for this. For C Flags and Linker Flags, also leave
 	// out the cross DSO flag which will be added separately under the correct conditions.
@@ -426,6 +426,8 @@
 	exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename)
 	exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag)
 
+	exportedVars.ExportString("NoSanitizeLinkRuntimeFlag", noSanitizeLinkRuntimeFlag)
+
 	android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
 	android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
 }
@@ -551,7 +553,9 @@
 		}
 
 		if found, globalSanitizers = removeFromList("hwaddress", globalSanitizers); found && s.Hwaddress == nil {
-			s.Hwaddress = proptools.BoolPtr(true)
+			if !ctx.Config().HWASanDisabledForPath(ctx.ModuleDir()) {
+				s.Hwaddress = proptools.BoolPtr(true)
+			}
 		}
 
 		if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
@@ -927,7 +931,7 @@
 			// Bionic and musl sanitizer runtimes have already been added as dependencies so that
 			// the right variant of the runtime will be used (with the "-android" or "-musl"
 			// suffixes), so don't let clang the runtime library.
-			flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-link-runtime")
+			flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag)
 		} else {
 			// Host sanitizers only link symbols in the final executable, so
 			// there will always be undefined symbols in intermediate libraries.
@@ -1187,7 +1191,7 @@
 	if sanitizeable, ok := ctx.Module().(Sanitizeable); ok {
 		enabled := sanitizeable.IsSanitizerEnabled(ctx.Config(), s.sanitizer.name())
 		ctx.VisitDirectDeps(func(dep android.Module) {
-			if c, ok := dep.(*Module); ok && c.sanitize.isSanitizerEnabled(s.sanitizer) {
+			if c, ok := dep.(PlatformSanitizeable); ok && c.IsSanitizerEnabled(s.sanitizer) {
 				enabled = true
 			}
 		})
@@ -1241,12 +1245,10 @@
 		}
 	}
 
-	if c, ok := ctx.Module().(*Module); ok {
-		//TODO: When Rust modules have vendor support, enable this path for PlatformSanitizeable
-
+	if c, ok := ctx.Module().(LinkableInterface); ok {
 		// Check if it's a snapshot module supporting sanitizer
-		if ss, ok := c.linker.(snapshotSanitizer); ok {
-			if ss.isSanitizerAvailable(s.sanitizer) {
+		if c.IsSnapshotSanitizer() {
+			if c.IsSnapshotSanitizerAvailable(s.sanitizer) {
 				return []string{"", s.sanitizer.variationName()}
 			} else {
 				return []string{""}
@@ -1278,8 +1280,8 @@
 
 func (s *sanitizerSplitMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string {
 	if d, ok := ctx.Module().(PlatformSanitizeable); ok {
-		if dm, ok := ctx.Module().(*Module); ok {
-			if ss, ok := dm.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) {
+		if dm, ok := ctx.Module().(LinkableInterface); ok {
+			if dm.IsSnapshotSanitizerAvailable(s.sanitizer) {
 				return incomingVariation
 			}
 		}
@@ -1394,19 +1396,19 @@
 		if sanitizerVariation {
 			sanitizeable.AddSanitizerDependencies(mctx, s.sanitizer.name())
 		}
-	} else if c, ok := mctx.Module().(*Module); ok {
-		if ss, ok := c.linker.(snapshotSanitizer); ok && ss.isSanitizerAvailable(s.sanitizer) {
-			if !ss.isUnsanitizedVariant() {
+	} else if c, ok := mctx.Module().(LinkableInterface); ok {
+		if c.IsSnapshotSanitizerAvailable(s.sanitizer) {
+			if !c.IsSnapshotUnsanitizedVariant() {
 				// Snapshot sanitizer may have only one variantion.
 				// Skip exporting the module if it already has a sanitizer variation.
 				c.SetPreventInstall()
 				c.SetHideFromMake()
 				return
 			}
-			c.linker.(snapshotSanitizer).setSanitizerVariation(s.sanitizer, sanitizerVariation)
+			c.SetSnapshotSanitizerVariation(s.sanitizer, sanitizerVariation)
 
 			// Export the static lib name to make
-			if c.static() && c.ExportedToMake() {
+			if c.Static() && c.ExportedToMake() {
 				// use BaseModuleName which is the name for Make.
 				if s.sanitizer == cfi {
 					cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
@@ -1418,6 +1420,35 @@
 	}
 }
 
+func (c *Module) IsSnapshotSanitizer() bool {
+	if _, ok := c.linker.(SnapshotSanitizer); ok {
+		return true
+	}
+	return false
+}
+
+func (c *Module) IsSnapshotSanitizerAvailable(t SanitizerType) bool {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		return ss.IsSanitizerAvailable(t)
+	}
+	return false
+}
+
+func (c *Module) SetSnapshotSanitizerVariation(t SanitizerType, enabled bool) {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		ss.SetSanitizerVariation(t, enabled)
+	} else {
+		panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", c.Name()))
+	}
+}
+
+func (c *Module) IsSnapshotUnsanitizedVariant() bool {
+	if ss, ok := c.linker.(SnapshotSanitizer); ok {
+		return ss.IsUnsanitizedVariant()
+	}
+	return false
+}
+
 func (c *Module) SanitizeNever() bool {
 	return Bool(c.sanitize.Properties.SanitizeMutated.Never)
 }
@@ -1648,12 +1679,12 @@
 			Bool(sanProps.Fuzzer) ||
 			Bool(sanProps.Undefined) ||
 			Bool(sanProps.All_undefined) {
-			if toolchain.Musl() || (c.staticBinary() && toolchain.Bionic()) {
-				// Use a static runtime for static binaries.
-				// Also use a static runtime for musl to match
-				// what clang does for glibc.  Otherwise dlopening
-				// libraries that depend on libclang_rt.ubsan_standalone.so
-				// fails with:
+			if toolchain.Musl() || c.staticBinary() {
+				// Use a static runtime for static binaries.  For sanitized glibc binaries the runtime is
+				// added automatically by clang, but for static glibc binaries that are not sanitized but
+				// have a sanitized dependency the runtime needs to be added manually.
+				// Also manually add a static runtime for musl to match what clang does for glibc.
+				// Otherwise dlopening libraries that depend on libclang_rt.ubsan_standalone.so fails with:
 				// Error relocating ...: initial-exec TLS resolves to dynamic definition
 				addStaticDeps(config.UndefinedBehaviorSanitizerRuntimeLibrary(toolchain)+".static", true)
 			} else {
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 29b17d4..49117a0 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -714,6 +714,15 @@
 			],
 		}
 
+		cc_binary {
+			name: "static_bin_with_ubsan_dep",
+			static_executable: true,
+			host_supported: true,
+			static_libs: [
+				"libubsan_diag",
+			],
+		}
+
 		cc_library_shared {
 			name: "libshared",
 			host_supported: true,
@@ -742,6 +751,17 @@
 		}
 
 		cc_library_static {
+			name: "libubsan_diag",
+			host_supported: true,
+			sanitize: {
+				undefined: true,
+				diag: {
+					undefined: true,
+				},
+			},
+		}
+
+		cc_library_static {
 			name: "libstatic",
 			host_supported: true,
 		}
@@ -763,6 +783,7 @@
 		sharedVariant := variant + "_shared"
 
 		minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant)
+		standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant)
 
 		// The binaries, one with ubsan and one without
 		binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant)
@@ -770,6 +791,7 @@
 		libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant)
 		binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant)
 		binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant)
+		staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant)
 
 		android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs",
 			strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "),
@@ -810,6 +832,11 @@
 		android.AssertStringListDoesNotContain(t, "unexpected -Wl,--exclude-libs for minimal runtime in bin_no_ubsan static libs",
 			strings.Split(binNoUbsan.Rule("ld").Args["ldFlags"], " "),
 			"-Wl,--exclude-libs="+minimalRuntime.OutputFiles(t, "")[0].Base())
+
+		android.AssertStringListContains(t, "missing libclang_rt.ubsan_standalone.static in static_bin_with_ubsan_dep static libs",
+			strings.Split(staticBin.Rule("ld").Args["libFlags"], " "),
+			standaloneRuntime.OutputFiles(t, "")[0].String())
+
 	}
 
 	t.Run("host", func(t *testing.T) { check(t, buildOS, preparer) })
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index bb13310..e29c446 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -403,11 +403,11 @@
 	Sanitize_minimal_dep *bool `android:"arch_variant"`
 }
 
-type snapshotSanitizer interface {
-	isSanitizerAvailable(t SanitizerType) bool
-	setSanitizerVariation(t SanitizerType, enabled bool)
-	isSanitizerEnabled(t SanitizerType) bool
-	isUnsanitizedVariant() bool
+type SnapshotSanitizer interface {
+	IsSanitizerAvailable(t SanitizerType) bool
+	SetSanitizerVariation(t SanitizerType, enabled bool)
+	IsSanitizerEnabled(t SanitizerType) bool
+	IsUnsanitizedVariant() bool
 }
 
 type snapshotLibraryDecorator struct {
@@ -460,9 +460,9 @@
 		return p.libraryDecorator.link(ctx, flags, deps, objs)
 	}
 
-	if p.isSanitizerEnabled(cfi) {
+	if p.IsSanitizerEnabled(cfi) {
 		p.properties = p.sanitizerProperties.Cfi
-	} else if p.isSanitizerEnabled(Hwasan) {
+	} else if p.IsSanitizerEnabled(Hwasan) {
 		p.properties = p.sanitizerProperties.Hwasan
 	}
 
@@ -526,9 +526,9 @@
 	return false
 }
 
-var _ snapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+var _ SnapshotSanitizer = (*snapshotLibraryDecorator)(nil)
 
-func (p *snapshotLibraryDecorator) isSanitizerAvailable(t SanitizerType) bool {
+func (p *snapshotLibraryDecorator) IsSanitizerAvailable(t SanitizerType) bool {
 	switch t {
 	case cfi:
 		return p.sanitizerProperties.Cfi.Src != nil
@@ -539,23 +539,23 @@
 	}
 }
 
-func (p *snapshotLibraryDecorator) setSanitizerVariation(t SanitizerType, enabled bool) {
-	if !enabled || p.isSanitizerEnabled(t) {
+func (p *snapshotLibraryDecorator) SetSanitizerVariation(t SanitizerType, enabled bool) {
+	if !enabled || p.IsSanitizerEnabled(t) {
 		return
 	}
-	if !p.isUnsanitizedVariant() {
+	if !p.IsUnsanitizedVariant() {
 		panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both"))
 	}
 	p.sanitizerProperties.SanitizerVariation = t
 }
 
-func (p *snapshotLibraryDecorator) isSanitizerEnabled(t SanitizerType) bool {
+func (p *snapshotLibraryDecorator) IsSanitizerEnabled(t SanitizerType) bool {
 	return p.sanitizerProperties.SanitizerVariation == t
 }
 
-func (p *snapshotLibraryDecorator) isUnsanitizedVariant() bool {
-	return !p.isSanitizerEnabled(Asan) &&
-		!p.isSanitizerEnabled(Hwasan)
+func (p *snapshotLibraryDecorator) IsUnsanitizedVariant() bool {
+	return !p.IsSanitizerEnabled(Asan) &&
+		!p.IsSanitizerEnabled(Hwasan)
 }
 
 func snapshotLibraryFactory(image SnapshotImage, moduleSuffix string) (*Module, *snapshotLibraryDecorator) {
diff --git a/cc/stl.go b/cc/stl.go
index ffc7c76..8f92dcb 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -80,8 +80,7 @@
 			return ""
 		}
 		s = deduplicateStlInput(s)
-		archHasNDKStl := ctx.Arch().ArchType != android.Riscv64
-		if ctx.useSdk() && ctx.Device() && archHasNDKStl {
+		if ctx.useSdk() && ctx.Device() {
 			switch s {
 			case "", "system":
 				return "ndk_system"
diff --git a/cc/test.go b/cc/test.go
index 3bba003..ae62128 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -267,7 +267,7 @@
 	return BoolDefault(test.LinkerProperties.Gtest, true)
 }
 
-func (test *testDecorator) isolated(ctx BaseModuleContext) bool {
+func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool {
 	return BoolDefault(test.LinkerProperties.Isolated, false)
 }
 
@@ -395,7 +395,7 @@
 
 	useVendor := ctx.inVendor() || ctx.useVndk()
 	testInstallBase := getTestInstallBase(useVendor)
-	configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx))
+	configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx), ctx.Device())
 
 	test.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
 		TestConfigProp:         test.Properties.Test_config,
@@ -435,22 +435,24 @@
 	return testInstallBase
 }
 
-func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool) []tradefed.Config {
+func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool, device bool) []tradefed.Config {
 	var configs []tradefed.Config
 
 	for _, module := range properties.Test_mainline_modules {
 		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
 	}
-	if Bool(properties.Require_root) {
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
-	} else {
-		var options []tradefed.Option
-		options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
-	}
-	if Bool(properties.Disable_framework) {
-		var options []tradefed.Option
-		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
+	if device {
+		if Bool(properties.Require_root) {
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
+		} else {
+			var options []tradefed.Option
+			options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
+		}
+		if Bool(properties.Disable_framework) {
+			var options []tradefed.Option
+			configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
+		}
 	}
 	if isolated {
 		configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"})
@@ -682,11 +684,12 @@
 type testBinaryAttributes struct {
 	binaryAttributes
 
-	Gtest    bool
-	Isolated bool
+	Gtest *bool
 
 	tidyAttributes
 	tradefed.TestConfigAttributes
+
+	Runs_on bazel.StringListAttribute
 }
 
 // testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
@@ -719,17 +722,34 @@
 		}
 	}
 
-	m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
-
-	for _, propIntf := range m.GetProperties() {
-		if testLinkerProps, ok := propIntf.(*TestLinkerProperties); ok {
-			testBinaryAttrs.Gtest = proptools.BoolDefault(testLinkerProps.Gtest, true)
-			testBinaryAttrs.Isolated = proptools.BoolDefault(testLinkerProps.Isolated, true)
-			break
+	// The logic comes from https://cs.android.com/android/platform/superproject/main/+/0df8153267f96da877febc5332240fa06ceb8533:build/soong/cc/sanitize.go;l=488
+	var features bazel.StringListAttribute
+	curFeatures := testBinaryAttrs.binaryAttributes.Features.SelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64)
+	var newFeatures []string
+	if !android.InList("memtag_heap", curFeatures) && !android.InList("-memtag_heap", curFeatures) {
+		newFeatures = append(newFeatures, "memtag_heap")
+		if !android.InList("diag_memtag_heap", curFeatures) && !android.InList("-diag_memtag_heap", curFeatures) {
+			newFeatures = append(newFeatures, "diag_memtag_heap")
 		}
 	}
 
-	addImplicitGtestDeps(ctx, &testBinaryAttrs)
+	features.SetSelectValue(bazel.OsArchConfigurationAxis, bazel.OsArchAndroidArm64, newFeatures)
+	testBinaryAttrs.binaryAttributes.Features.Append(features)
+	testBinaryAttrs.binaryAttributes.Features.DeduplicateAxesFromBase()
+
+	m.convertTidyAttributes(ctx, &testBinaryAttrs.tidyAttributes)
+
+	testBinary := m.linker.(*testBinary)
+	gtest := testBinary.gtest()
+	gtestIsolated := testBinary.isolated(ctx)
+	// Use the underling bool pointer for Gtest in attrs
+	// This ensures that if this property is not set in Android.bp file, it will not be set in BUILD file either
+	// cc_test macro will default gtest to True
+	testBinaryAttrs.Gtest = testBinary.LinkerProperties.Gtest
+
+	addImplicitGtestDeps(ctx, &testBinaryAttrs, gtest, gtestIsolated)
+
+	var unitTest *bool
 
 	for _, testProps := range m.GetProperties() {
 		if p, ok := testProps.(*TestBinaryProperties); ok {
@@ -742,13 +762,19 @@
 				p.Auto_gen_config,
 				p.Test_options.Test_suite_tag,
 				p.Test_config_template,
-				getTradefedConfigOptions(ctx, p, testBinaryAttrs.Isolated),
+				getTradefedConfigOptions(ctx, p, gtestIsolated, true),
 				&testInstallBase,
 			)
 			testBinaryAttrs.TestConfigAttributes = testConfigAttributes
+			unitTest = p.Test_options.Unit_test
 		}
 	}
 
+	testBinaryAttrs.Runs_on = bazel.MakeStringListAttribute(android.RunsOn(
+		m.ModuleBase.HostSupported(),
+		m.ModuleBase.DeviceSupported(),
+		gtest || (unitTest != nil && *unitTest)))
+
 	// TODO (b/262914724): convert to tradefed_cc_test and tradefed_cc_test_host
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
@@ -765,18 +791,25 @@
 
 // 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) {
-	if attrs.Gtest {
-		gtestDeps := android.BazelLabelForModuleDeps(
-			ctx,
-			[]string{
+func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
+	addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
+		moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
+		lla.Value.Append(moduleLabels)
+		// Dedupe
+		lla.Value = bazel.FirstUniqueBazelLabelList(lla.Value)
+	}
+	// this must be kept in sync with Soong's implementation in:
+	// https://cs.android.com/android/_/android/platform/build/soong/+/460fb2d6d546b5ab493a7e5479998c4933a80f73:cc/test.go;l=300-313;drc=ec7314336a2b35ea30ce5438b83949c28e3ac429;bpv=1;bpt=0
+	if gtest {
+		// TODO - b/244433197: Handle canUseSdk
+		if gtestIsolated {
+			addDepsAndDedupe(&attrs.Deps, []string{"libgtest_isolated_main"})
+			addDepsAndDedupe(&attrs.Dynamic_deps, []string{"liblog"})
+		} else {
+			addDepsAndDedupe(&attrs.Deps, []string{
 				"libgtest_main",
 				"libgtest",
-			},
-		)
-		attrs.Deps.Value.Append(gtestDeps)
-		// Dedupe
-		attrs.Deps.Value = bazel.FirstUniqueBazelLabelList(attrs.Deps.Value)
+			})
+		}
 	}
-	// TODO(b/244432609): handle `isolated` property.
 }
diff --git a/cc/vndk.go b/cc/vndk.go
index 7a2286e..5ac5032 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -39,25 +39,46 @@
 	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
 )
 
-func VndkLibrariesTxtModules(vndkVersion string) []string {
+func VndkLibrariesTxtModules(vndkVersion string, ctx android.BaseModuleContext) []string {
 	if vndkVersion == "current" {
-		return []string{
-			llndkLibrariesTxt,
-			vndkCoreLibrariesTxt,
-			vndkSpLibrariesTxt,
-			vndkPrivateLibrariesTxt,
-			vndkProductLibrariesTxt,
+		// We can assume all txt files are snapshotted if we find one of them.
+		currentVndkSnapshotted := ctx.OtherModuleExists(insertVndkVersion(llndkLibrariesTxt, ctx.DeviceConfig().PlatformVndkVersion()))
+		if currentVndkSnapshotted {
+			// If the current VNDK is already snapshotted (which can happen with
+			// the `next` config), use the prebuilt txt files in the snapshot.
+			// This is because the txt files built from source are probably be
+			// for the in-development version.
+			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
+		} else {
+			// Use the txt files generated from the source
+			result := []string{
+				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
 		}
 	}
+
 	// Snapshot vndks have their own *.libraries.VER.txt files.
 	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
-	return []string{
-		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
+	result := []string{
 		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
 		insertVndkVersion(vndkProductLibrariesTxt, vndkVersion),
+		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
 	}
+
+	return result
 }
 
 type VndkProperties struct {
@@ -352,11 +373,19 @@
 		return false
 	}
 
-	// prebuilt vndk modules should match with device
 	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
 	// When b/142675459 is landed, remove following check
-	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) {
-		return false
+	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok {
+		// prebuilt vndk modules should match with device
+		if !p.MatchesWithDevice(mctx.DeviceConfig()) {
+			return false
+		}
+
+		// ignore prebuilt vndk modules that are newer than or equal to the platform vndk version
+		platformVndkApiLevel := android.ApiLevelOrPanic(mctx, mctx.DeviceConfig().PlatformVndkVersion())
+		if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(mctx, p.Version())) {
+			return false
+		}
 	}
 
 	if lib, ok := m.linker.(libraryInterface); ok {
@@ -518,12 +547,25 @@
 	return filename
 }
 
+func (txt *vndkLibrariesTxt) DepsMutator(mctx android.BottomUpMutatorContext) {
+	versionedName := insertVndkVersion(txt.Name(), mctx.DeviceConfig().PlatformVndkVersion())
+	if mctx.OtherModuleExists(versionedName) {
+		// If the prebuilt vndk libraries txt files exist, install them instead.
+		txt.HideFromMake()
+		mctx.AddDependency(txt, nil, versionedName)
+	}
+}
+
 func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	var filename string
-	if BoolDefault(txt.properties.Insert_vndk_version, true) {
+	filename := 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())
-	} else {
-		filename = txt.Name()
 	}
 
 	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 37819a4..5e526db 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -131,6 +131,12 @@
 
 func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext,
 	flags Flags, deps PathDeps, objs Objects) android.Path {
+	platformVndkApiLevel := android.ApiLevelOrPanic(ctx, ctx.DeviceConfig().PlatformVndkVersion())
+	if platformVndkApiLevel.LessThanOrEqualTo(android.ApiLevelOrPanic(ctx, p.Version())) {
+		// This prebuilt VNDK module is not required for the current build
+		ctx.Module().HideFromMake()
+		return nil
+	}
 
 	if !p.MatchesWithDevice(ctx.DeviceConfig()) {
 		ctx.Module().HideFromMake()
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 5ea84bc..626f076 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -27,7 +27,6 @@
 
 	"android/soong/android"
 	"android/soong/android/allowlists"
-	"android/soong/bazel"
 	"android/soong/bp2build"
 	"android/soong/shared"
 	"android/soong/ui/metrics/bp2build_metrics_proto"
@@ -76,7 +75,6 @@
 	flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
 	flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output")
 	flag.StringVar(&cmdlineArgs.BazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
-	flag.StringVar(&cmdlineArgs.BazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top")
 	flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
 	flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
 	flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
@@ -121,6 +119,10 @@
 	defer ctx.EventHandler.End("mixed_build")
 
 	bazelHook := func() error {
+		err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config())
+		if err != nil {
+			return err
+		}
 		return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
 	}
 	ctx.SetBeforePrepareBuildActionsHook(bazelHook)
@@ -165,120 +167,6 @@
 	touch(shared.JoinPath(topDir, queryviewMarker))
 }
 
-// Run the code-generation phase to convert API contributions to BUILD files.
-// Return marker file for the new synthetic workspace
-func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string {
-	ctx.EventHandler.Begin("api_bp2build")
-	defer ctx.EventHandler.End("api_bp2build")
-	// api_bp2build does not run the typical pipeline of soong mutators.
-	// Hoevever, it still runs the defaults mutator which can create dependencies.
-	// These dependencies might not always exist (e.g. in tests)
-	ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
-	ctx.RegisterForApiBazelConversion()
-
-	// Register the Android.bp files in the tree
-	// Add them to the workspace's .d file
-	ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
-	if paths, err := ctx.ListModulePaths("."); err == nil {
-		extraNinjaDeps = append(extraNinjaDeps, paths...)
-	} else {
-		panic(err)
-	}
-
-	// Run the loading and analysis phase
-	ninjaDeps, err := bootstrap.RunBlueprint(cmdlineArgs.Args,
-		bootstrap.StopBeforePrepareBuildActions,
-		ctx.Context,
-		ctx.Config())
-	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
-	// Add the globbed dependencies
-	ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
-
-	// Run codegen to generate BUILD files
-	codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build, topDir)
-	absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir)
-	// Always generate bp2build_all_srcs filegroups in api_bp2build.
-	// This is necessary to force each Android.bp file to create an equivalent BUILD file
-	// and prevent package boundray issues.
-	// e.g.
-	// Source
-	// f/b/Android.bp
-	// java_library{
-	//   name: "foo",
-	//   api: "api/current.txt",
-	// }
-	//
-	// f/b/api/Android.bp <- will cause package boundary issues
-	//
-	// Gen
-	// f/b/BUILD
-	// java_contribution{
-	//   name: "foo.contribution",
-	//   api: "//f/b/api:current.txt",
-	// }
-	//
-	// If we don't generate f/b/api/BUILD, foo.contribution will be unbuildable.
-	err = createBazelWorkspace(codegenContext, absoluteApiBp2buildDir, true)
-	maybeQuit(err, "")
-	ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
-
-	// Create soong_injection repository
-	soongInjectionFiles, workspaceFiles, err := bp2build.CreateSoongInjectionDirFiles(codegenContext, bp2build.CreateCodegenMetrics())
-	maybeQuit(err, "")
-	absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
-	for _, file := range soongInjectionFiles {
-		// The API targets in api_bp2build workspace do not have any dependency on api_bp2build.
-		// But we need to create these files to prevent errors during Bazel analysis.
-		// These need to be created in Read-Write mode.
-		// This is because the subsequent step (bp2build in api domain analysis) creates them in Read-Write mode
-		// to allow users to edit/experiment in the synthetic workspace.
-		writeReadWriteFile(absoluteSoongInjectionDir, file)
-	}
-	for _, file := range workspaceFiles {
-		writeReadWriteFile(absoluteApiBp2buildDir, file)
-	}
-
-	workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build")
-	// Create the symlink forest
-	symlinkDeps, _, _ := bp2build.PlantSymlinkForest(
-		ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE"),
-		topDir,
-		workspace,
-		cmdlineArgs.BazelApiBp2buildDir,
-		apiBuildFileExcludes(ctx))
-	ninjaDeps = append(ninjaDeps, symlinkDeps...)
-
-	workspaceMarkerFile := workspace + ".marker"
-	writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps)
-	touch(shared.JoinPath(topDir, workspaceMarkerFile))
-	return workspaceMarkerFile
-}
-
-// With some exceptions, api_bp2build does not have any dependencies on the checked-in BUILD files
-// Exclude them from the generated workspace to prevent unrelated errors during the loading phase
-func apiBuildFileExcludes(ctx *android.Context) []string {
-	ret := bazelArtifacts()
-	srcs, err := getExistingBazelRelatedFiles(topDir)
-	maybeQuit(err, "Error determining existing Bazel-related files")
-	for _, src := range srcs {
-		// Exclude all src BUILD files
-		if src != "WORKSPACE" &&
-			src != "BUILD" &&
-			src != "BUILD.bazel" &&
-			!strings.HasPrefix(src, "build/bazel") &&
-			!strings.HasPrefix(src, "external/bazel-skylib") &&
-			!strings.HasPrefix(src, "prebuilts/clang") {
-			ret = append(ret, src)
-		}
-	}
-	// Android.bp files for api surfaces are mounted to out/, but out/ should not be a
-	// dep for api_bp2build. Otherwise, api_bp2build will be run every single time
-	ret = append(ret, ctx.Config().OutDir())
-	return ret
-}
-
 func writeNinjaHint(ctx *android.Context) error {
 	ctx.BeginEvent("ninja_hint")
 	defer ctx.EndEvent("ninja_hint")
@@ -547,9 +435,6 @@
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
 		// Blueprint to BUILD files before everything else.
 		finalOutputFile = runBp2Build(ctx, extraNinjaDeps, metricsDir)
-	case android.ApiBp2build:
-		finalOutputFile = runApiBp2build(ctx, extraNinjaDeps)
-		writeMetrics(configuration, ctx.EventHandler, metricsDir)
 	default:
 		ctx.Register()
 		isMixedBuildsEnabled := configuration.IsMixedBuildsEnabled()
@@ -810,9 +695,7 @@
 		// Run the code-generation phase to convert BazelTargetModules to BUILD files
 		// and print conversion codegenMetrics to the user.
 		codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build, topDir)
-		ctx.EventHandler.Do("codegen", func() {
-			codegenMetrics = bp2build.Codegen(codegenContext)
-		})
+		codegenMetrics = bp2build.Codegen(codegenContext)
 
 		ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
 
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 67cb6cf..5c2316a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,7 +15,6 @@
 package main
 
 import (
-	"android/soong/starlark_import"
 	"io/fs"
 	"io/ioutil"
 	"os"
@@ -23,6 +22,7 @@
 
 	"android/soong/android"
 	"android/soong/bp2build"
+	"android/soong/starlark_import"
 )
 
 // A helper function to generate a Read-only Bazel workspace in outDir
@@ -35,8 +35,7 @@
 		panic(err)
 	}
 
-	filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
-		ctx.Mode())
+	filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
 	bazelRcFiles, err2 := CopyBazelRcFiles()
 	if err2 != nil {
 		return err2
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index c238098..85a69ef 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -471,6 +471,56 @@
 	}
 }
 
+// TestZip2Zip64 tests that zip2zip on zip file larger than 4GB produces a valid zip file.
+func TestZip2Zip64(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping slow test in short mode")
+	}
+	inputBuf := &bytes.Buffer{}
+	outputBuf := &bytes.Buffer{}
+
+	inputWriter := zip.NewWriter(inputBuf)
+	w, err := inputWriter.CreateHeaderAndroid(&zip.FileHeader{
+		Name:   "a",
+		Method: zip.Store,
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	buf := make([]byte, 4*1024*1024)
+	for i := 0; i < 1025; i++ {
+		w.Write(buf)
+	}
+	w, err = inputWriter.CreateHeaderAndroid(&zip.FileHeader{
+		Name:   "b",
+		Method: zip.Store,
+	})
+	for i := 0; i < 1025; i++ {
+		w.Write(buf)
+	}
+	inputWriter.Close()
+	inputBytes := inputBuf.Bytes()
+
+	inputReader, err := zip.NewReader(bytes.NewReader(inputBytes), int64(len(inputBytes)))
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	outputWriter := zip.NewWriter(outputBuf)
+	err = zip2zip(inputReader, outputWriter, false, false, false,
+		nil, nil, nil, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	outputWriter.Close()
+	outputBytes := outputBuf.Bytes()
+	_, err = zip.NewReader(bytes.NewReader(outputBytes), int64(len(outputBytes)))
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func TestConstantPartOfPattern(t *testing.T) {
 	testCases := []struct{ in, out string }{
 		{
diff --git a/etc/Android.bp b/etc/Android.bp
index c670236..cefd717 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -14,10 +14,12 @@
     srcs: [
         "prebuilt_etc.go",
         "snapshot_etc.go",
+        "install_symlink.go",
     ],
     testSrcs: [
         "prebuilt_etc_test.go",
         "snapshot_etc_test.go",
+        "install_symlink_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/etc/install_symlink.go b/etc/install_symlink.go
new file mode 100644
index 0000000..2182b86
--- /dev/null
+++ b/etc/install_symlink.go
@@ -0,0 +1,92 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"android/soong/android"
+	"path/filepath"
+	"strings"
+)
+
+func init() {
+	RegisterInstallSymlinkBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterInstallSymlinkBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("install_symlink", InstallSymlinkFactory)
+}
+
+// install_symlink can be used to install an symlink with an arbitrary target to an arbitrary path
+// on the device.
+func InstallSymlinkFactory() android.Module {
+	module := &InstallSymlink{}
+	module.AddProperties(&module.properties)
+	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+type InstallSymlinkProperties struct {
+	// Where to install this symlink, relative to the partition it's installed on.
+	// Which partition it's installed on can be controlled by the vendor, system_ext, ramdisk, etc.
+	// properties.
+	Installed_location string
+	// The target of the symlink, aka where the symlink points.
+	Symlink_target string
+}
+
+type InstallSymlink struct {
+	android.ModuleBase
+	properties InstallSymlinkProperties
+
+	output        android.Path
+	installedPath android.InstallPath
+}
+
+func (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if filepath.Clean(m.properties.Symlink_target) != m.properties.Symlink_target {
+		ctx.PropertyErrorf("symlink_target", "Should be a clean filepath")
+		return
+	}
+	if filepath.Clean(m.properties.Installed_location) != m.properties.Installed_location {
+		ctx.PropertyErrorf("installed_location", "Should be a clean filepath")
+		return
+	}
+	if strings.HasPrefix(m.properties.Installed_location, "../") || strings.HasPrefix(m.properties.Installed_location, "/") {
+		ctx.PropertyErrorf("installed_location", "Should not start with / or ../")
+		return
+	}
+
+	out := android.PathForModuleOut(ctx, "out.txt")
+	android.WriteFileRuleVerbatim(ctx, out, "")
+	m.output = out
+
+	name := filepath.Base(m.properties.Installed_location)
+	installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location))
+	m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, m.properties.Symlink_target)
+}
+
+func (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{{
+		Class: "FAKE",
+		// Need at least one output file in order for this to take effect.
+		OutputFile: android.OptionalPathForPath(m.output),
+		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", m.installedPath.String())
+			},
+		},
+	}}
+}
diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go
new file mode 100644
index 0000000..d7165e5
--- /dev/null
+++ b/etc/install_symlink_test.go
@@ -0,0 +1,135 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"android/soong/android"
+	"strings"
+	"testing"
+)
+
+var prepareForInstallSymlinkTest = android.GroupFixturePreparers(
+	android.PrepareForTestWithArchMutator,
+	android.FixtureRegisterWithContext(RegisterInstallSymlinkBuildComponents),
+)
+
+func TestInstallSymlinkBasic(t *testing.T) {
+	result := prepareForInstallSymlinkTest.RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+
+	foo_variants := result.ModuleVariantsForTests("foo")
+	if len(foo_variants) != 1 {
+		t.Fatalf("expected 1 variant, got %#v", foo_variants)
+	}
+
+	foo := result.ModuleForTests("foo", "android_common").Module()
+	androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+	if len(androidMkEntries) != 1 {
+		t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+	}
+
+	symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+	if len(symlinks) != 1 {
+		t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+	}
+
+	if !strings.HasSuffix(symlinks[0], "system/bin/foo") {
+		t.Fatalf("Expected symlink install path to end in system/bin/foo, got: %s", symlinks[0])
+	}
+}
+
+func TestInstallSymlinkToRecovery(t *testing.T) {
+	result := prepareForInstallSymlinkTest.RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+			recovery: true,
+		}
+	`)
+
+	foo_variants := result.ModuleVariantsForTests("foo")
+	if len(foo_variants) != 1 {
+		t.Fatalf("expected 1 variant, got %#v", foo_variants)
+	}
+
+	foo := result.ModuleForTests("foo", "android_common").Module()
+	androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo)
+	if len(androidMkEntries) != 1 {
+		t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries))
+	}
+
+	symlinks := androidMkEntries[0].EntryMap["LOCAL_SOONG_INSTALL_SYMLINKS"]
+	if len(symlinks) != 1 {
+		t.Fatalf("Expected 1 symlink, got %d", len(symlinks))
+	}
+
+	if !strings.HasSuffix(symlinks[0], "recovery/root/system/bin/foo") {
+		t.Fatalf("Expected symlink install path to end in recovery/root/system/bin/foo, got: %s", symlinks[0])
+	}
+}
+
+func TestErrorOnNonCleanTarget(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/foo",
+			symlink_target: "/system/system_ext/../bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnNonCleanInstalledLocation(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should be a clean filepath")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "bin/../foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnInstalledPathStartingWithDotDot(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "../bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
+
+func TestErrorOnInstalledPathStartingWithSlash(t *testing.T) {
+	prepareForInstallSymlinkTest.
+		ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Should not start with / or \\.\\./")).
+		RunTestWithBp(t, `
+		install_symlink {
+			name: "foo",
+			installed_location: "/bin/foo",
+			symlink_target: "/system/system_ext/bin/foo",
+		}
+	`)
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 370a423..c48bafa 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -40,6 +40,7 @@
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/snapshot"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 )
 
 var pctx = android.NewPackageContext("android/soong/etc")
@@ -711,7 +712,7 @@
 // Bp2buildHelper returns a bazelPrebuiltFileAttributes used for the conversion
 // of prebuilt_*  modules. bazelPrebuiltFileAttributes has the common attributes
 // used by both prebuilt_etc_xml and other prebuilt_* moodules
-func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) *bazelPrebuiltFileAttributes {
+func (module *PrebuiltEtc) Bp2buildHelper(ctx android.TopDownMutatorContext) (*bazelPrebuiltFileAttributes, bool) {
 	var src bazel.LabelAttribute
 	for axis, configToProps := range module.GetArchVariantProperties(ctx, &prebuiltEtcProperties{}) {
 		for config, p := range configToProps {
@@ -720,7 +721,12 @@
 				continue
 			}
 			if props.Src != nil {
-				label := android.BazelLabelForModuleSrcSingle(ctx, *props.Src)
+				srcStr := proptools.String(props.Src)
+				if srcStr == ctx.ModuleName() {
+					ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "src == name")
+					return &bazelPrebuiltFileAttributes{}, false
+				}
+				label := android.BazelLabelForModuleSrcSingle(ctx, srcStr)
 				src.SetSelectValue(axis, config, label)
 			}
 		}
@@ -779,8 +785,7 @@
 		attrs.Filename_from_src = bazel.BoolAttribute{Value: moduleProps.Filename_from_src}
 	}
 
-	return attrs
-
+	return attrs, true
 }
 
 // ConvertWithBp2build performs bp2build conversion of PrebuiltEtc
@@ -793,7 +798,10 @@
 		return
 	}
 
-	attrs := module.Bp2buildHelper(ctx)
+	attrs, convertible := module.Bp2buildHelper(ctx)
+	if !convertible {
+		return
+	}
 
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        "prebuilt_file",
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index df7664d..5c4e222 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -83,7 +83,7 @@
 
 	baz_variants := result.ModuleVariantsForTests("baz.conf")
 	if len(baz_variants) != 1 {
-		t.Errorf("expected 1, got %#v", bar_variants)
+		t.Errorf("expected 1, got %#v", baz_variants)
 	}
 }
 
diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go
index f3fecd0..dabbc46 100644
--- a/filesystem/avb_add_hash_footer.go
+++ b/filesystem/avb_add_hash_footer.go
@@ -68,6 +68,9 @@
 	// List of properties to add to the footer
 	Props []avbProp
 
+	// The index used to prevent rollback of the image on device.
+	Rollback_index *int64
+
 	// Include descriptors from images
 	Include_descriptors_from_images []string `android:"path,arch_variant"`
 }
@@ -128,6 +131,14 @@
 		addAvbProp(ctx, cmd, prop)
 	}
 
+	if a.properties.Rollback_index != nil {
+		rollbackIndex := proptools.Int(a.properties.Rollback_index)
+		if rollbackIndex < 0 {
+			ctx.PropertyErrorf("rollback_index", "Rollback index must be non-negative")
+		}
+		cmd.Flag(fmt.Sprintf(" --rollback_index %x", rollbackIndex))
+	}
+
 	cmd.FlagWithOutput("--image ", a.output)
 
 	builder.Build("avbAddHashFooter", fmt.Sprintf("avbAddHashFooter %s", ctx.ModuleName()))
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 6306c27..d1c2f13 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -140,7 +140,7 @@
 	// prebuilts or scripts that do not need a module to build them.
 	Tools []string
 
-	// Local file that is used as the tool
+	// Local files that are used by the tool
 	Tool_files []string `android:"path"`
 
 	// List of directories to export generated headers from
@@ -403,7 +403,6 @@
 	}
 
 	addLabelsForInputs := func(propName string, include, exclude []string) android.Paths {
-
 		includeDirInPaths := ctx.DeviceConfig().BuildBrokenInputDir(g.Name())
 		var srcFiles android.Paths
 		for _, in := range include {
@@ -869,7 +868,7 @@
 	Srcs             bazel.LabelListAttribute
 	Output_extension *string
 	Tools            bazel.LabelListAttribute
-	Cmd              string
+	Cmd              bazel.StringAttribute
 	Data             bazel.LabelListAttribute
 }
 
@@ -913,11 +912,11 @@
 	Out []string
 }
 
-type bazelGenruleAttributes struct {
+type BazelGenruleAttributes struct {
 	Srcs  bazel.LabelListAttribute
 	Outs  []string
 	Tools bazel.LabelListAttribute
-	Cmd   string
+	Cmd   bazel.StringAttribute
 }
 
 // ConvertWithBp2build converts a Soong module -> Bazel target.
@@ -967,14 +966,13 @@
 		}
 	}
 
-	// Replace in and out variables with $< and $@
-	var cmd string
-	if m.properties.Cmd != nil {
+	replaceVariables := func(cmd string) string {
+		// Replace in and out variables with $< and $@
 		if ctx.ModuleType() == "gensrcs" {
-			cmd = strings.ReplaceAll(*m.properties.Cmd, "$(in)", "$(SRC)")
+			cmd = strings.ReplaceAll(cmd, "$(in)", "$(SRC)")
 			cmd = strings.ReplaceAll(cmd, "$(out)", "$(OUT)")
 		} else {
-			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+			cmd = strings.Replace(cmd, "$(in)", "$(SRCS)", -1)
 			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
 		}
 		cmd = strings.Replace(cmd, "$(genDir)", "$(RULEDIR)", -1)
@@ -990,10 +988,26 @@
 			cmd = strings.Replace(cmd, bpLoc, bazelLoc, -1)
 			cmd = strings.Replace(cmd, bpLocs, bazelLocs, -1)
 		}
+		return cmd
+	}
+
+	var cmdProp bazel.StringAttribute
+	cmdProp.SetValue(replaceVariables(proptools.String(m.properties.Cmd)))
+	allProductVariableProps := android.ProductVariableProperties(ctx, m)
+	if productVariableProps, ok := allProductVariableProps["Cmd"]; ok {
+		for productVariable, value := range productVariableProps {
+			var cmd string
+			if strValue, ok := value.(*string); ok && strValue != nil {
+				cmd = *strValue
+			}
+			cmd = replaceVariables(cmd)
+			cmdProp.SetSelectValue(productVariable.ConfigurationAxis(), productVariable.SelectKey(), &cmd)
+		}
 	}
 
 	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 
+	bazelName := m.Name()
 	if ctx.ModuleType() == "gensrcs" {
 		props := bazel.BazelTargetModuleProperties{
 			Rule_class:        "gensrcs",
@@ -1002,7 +1016,7 @@
 		attrs := &bazelGensrcsAttributes{
 			Srcs:             srcs,
 			Output_extension: outputExtension,
-			Cmd:              cmd,
+			Cmd:              cmdProp,
 			Tools:            tools,
 			Data:             data,
 		}
@@ -1011,17 +1025,7 @@
 			Tags: tags,
 		}, attrs)
 	} else {
-		// The Out prop is not in an immediately accessible field
-		// in the Module struct, so use GetProperties and cast it
-		// to the known struct prop.
-		var outs []string
-		for _, propIntf := range m.GetProperties() {
-			if props, ok := propIntf.(*genRuleProperties); ok {
-				outs = props.Out
-				break
-			}
-		}
-		bazelName := m.Name()
+		outs := m.RawOutputFiles(ctx)
 		for _, out := range outs {
 			if out == bazelName {
 				// This is a workaround to circumvent a Bazel warning where a genrule's
@@ -1032,10 +1036,10 @@
 				break
 			}
 		}
-		attrs := &bazelGenruleAttributes{
+		attrs := &BazelGenruleAttributes{
 			Srcs:  srcs,
 			Outs:  outs,
-			Cmd:   cmd,
+			Cmd:   cmdProp,
 			Tools: tools,
 		}
 		props := bazel.BazelTargetModuleProperties{
@@ -1046,6 +1050,72 @@
 			Tags: tags,
 		}, attrs)
 	}
+
+	if m.needsCcLibraryHeadersBp2build() {
+		includeDirs := make([]string, len(m.properties.Export_include_dirs)*2)
+		for i, dir := range m.properties.Export_include_dirs {
+			includeDirs[i*2] = dir
+			includeDirs[i*2+1] = filepath.Clean(filepath.Join(ctx.ModuleDir(), dir))
+		}
+		attrs := &ccHeaderLibraryAttrs{
+			Hdrs:            []string{":" + bazelName},
+			Export_includes: includeDirs,
+		}
+		props := bazel.BazelTargetModuleProperties{
+			Rule_class:        "cc_library_headers",
+			Bzl_load_location: "//build/bazel/rules/cc:cc_library_headers.bzl",
+		}
+		ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+			Name: m.Name() + genruleHeaderLibrarySuffix,
+			Tags: tags,
+		}, attrs)
+	}
+}
+
+const genruleHeaderLibrarySuffix = "__header_library"
+
+func (m *Module) needsCcLibraryHeadersBp2build() bool {
+	return len(m.properties.Export_include_dirs) > 0
+}
+
+// GenruleCcHeaderMapper is a bazel.LabelMapper function to map genrules to a cc_library_headers
+// target when they export multiple include directories.
+func GenruleCcHeaderLabelMapper(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+	mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+	if !exists {
+		return label.Label, false
+	}
+	if m, ok := mod.(*Module); ok {
+		if m.needsCcLibraryHeadersBp2build() {
+			return label.Label + genruleHeaderLibrarySuffix, true
+		}
+	}
+	return label.Label, false
+}
+
+type ccHeaderLibraryAttrs struct {
+	Hdrs []string
+
+	Export_includes []string
+}
+
+// RawOutputFfiles returns the raw outputs specified in Android.bp
+// This does not contain the fully resolved path relative to the top of the tree
+func (g *Module) RawOutputFiles(ctx android.BazelConversionContext) []string {
+	if ctx.Config().BuildMode != android.Bp2build {
+		ctx.ModuleErrorf("RawOutputFiles is only supported in bp2build mode")
+	}
+	// The Out prop is not in an immediately accessible field
+	// in the Module struct, so use GetProperties and cast it
+	// to the known struct prop.
+	var outs []string
+	for _, propIntf := range g.GetProperties() {
+		if props, ok := propIntf.(*genRuleProperties); ok {
+			outs = props.Out
+			break
+		}
+	}
+	return outs
 }
 
 var Bool = proptools.Bool
@@ -1099,6 +1169,7 @@
 		}
 	}).(*sandboxingAllowlistSets)
 }
+
 func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder {
 	if !ctx.DeviceConfig().GenruleSandboxing() {
 		return r.SandboxTools()
diff --git a/java/aapt2.go b/java/aapt2.go
index 7845a0b..3bb70b5 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -146,20 +146,25 @@
 
 var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
 	blueprint.RuleParams{
-		Command: `rm -rf $genDir && ` +
-			`${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` +
-			`--output-text-symbols ${rTxt} $inFlags && ` +
-			`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` +
-			`${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`,
+		Command: `$preamble` +
+			`${config.Aapt2Cmd} link -o $out $flags --proguard $proguardOptions ` +
+			`--output-text-symbols ${rTxt} $inFlags` +
+			`$postamble`,
 
 		CommandDeps: []string{
 			"${config.Aapt2Cmd}",
 			"${config.SoongZipCmd}",
-			"${config.ExtractJarPackagesCmd}",
 		},
 		Restat: true,
 	},
-	"flags", "inFlags", "proguardOptions", "genDir", "genJar", "rTxt", "extraPackages")
+	"flags", "inFlags", "proguardOptions", "rTxt", "extraPackages", "preamble", "postamble")
+
+var aapt2ExtractExtraPackagesRule = pctx.AndroidStaticRule("aapt2ExtractExtraPackages",
+	blueprint.RuleParams{
+		Command:     `${config.ExtractJarPackagesCmd} -i $in -o $out --prefix '--extra-packages '`,
+		CommandDeps: []string{"${config.ExtractJarPackagesCmd}"},
+		Restat:      true,
+	})
 
 var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
 	blueprint.RuleParams{
@@ -175,12 +180,10 @@
 	})
 
 func aapt2Link(ctx android.ModuleContext,
-	packageRes, genJar, proguardOptions, rTxt, extraPackages android.WritablePath,
+	packageRes, genJar, proguardOptions, rTxt android.WritablePath,
 	flags []string, deps android.Paths,
 	compiledRes, compiledOverlay, assetPackages android.Paths, splitPackages android.WritablePaths) {
 
-	genDir := android.PathForModuleGen(ctx, "aapt2", "R")
-
 	var inFlags []string
 
 	if len(compiledRes) > 0 {
@@ -217,7 +220,7 @@
 	}
 
 	// Set auxiliary outputs as implicit outputs to establish correct dependency chains.
-	implicitOutputs := append(splitPackages, proguardOptions, genJar, rTxt, extraPackages)
+	implicitOutputs := append(splitPackages, proguardOptions, rTxt)
 	linkOutput := packageRes
 
 	// AAPT2 ignores assets in overlays. Merge them after linking.
@@ -232,25 +235,49 @@
 		})
 	}
 
+	// Note the absence of splitPackages. The caller is supposed to compose and provide --split flag
+	// values via the flags parameter when it wants to split outputs.
+	// TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably
+	// tidy.
+	args := map[string]string{
+		"flags":           strings.Join(flags, " "),
+		"inFlags":         strings.Join(inFlags, " "),
+		"proguardOptions": proguardOptions.String(),
+		"rTxt":            rTxt.String(),
+	}
+
+	if genJar != nil {
+		// Generating java source files from aapt2 was requested, use aapt2LinkAndGenRule and pass it
+		// genJar and genDir args.
+		genDir := android.PathForModuleGen(ctx, "aapt2", "R")
+		ctx.Variable(pctx, "aapt2GenDir", genDir.String())
+		ctx.Variable(pctx, "aapt2GenJar", genJar.String())
+		implicitOutputs = append(implicitOutputs, genJar)
+		args["preamble"] = `rm -rf $aapt2GenDir && `
+		args["postamble"] = `&& ${config.SoongZipCmd} -write_if_changed -jar -o $aapt2GenJar -C $aapt2GenDir -D $aapt2GenDir && ` +
+			`rm -rf $aapt2GenDir`
+		args["flags"] += " --java $aapt2GenDir"
+	}
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            aapt2LinkRule,
 		Description:     "aapt2 link",
 		Implicits:       deps,
 		Output:          linkOutput,
 		ImplicitOutputs: implicitOutputs,
-		// Note the absence of splitPackages. The caller is supposed to compose and provide --split flag
-		// values via the flags parameter when it wants to split outputs.
-		// TODO(b/174509108): Perhaps we can process it in this func while keeping the code reasonably
-		// tidy.
-		Args: map[string]string{
-			"flags":           strings.Join(flags, " "),
-			"inFlags":         strings.Join(inFlags, " "),
-			"proguardOptions": proguardOptions.String(),
-			"genDir":          genDir.String(),
-			"genJar":          genJar.String(),
-			"rTxt":            rTxt.String(),
-			"extraPackages":   extraPackages.String(),
-		},
+		Args:            args,
+	})
+}
+
+// aapt2ExtractExtraPackages takes a srcjar generated by aapt2 or a classes jar generated by ResourceProcessorBusyBox
+// and converts it to a text file containing a list of --extra_package arguments for passing to Make modules so they
+// correctly generate R.java entries for packages provided by transitive dependencies.
+func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePath, in android.Path) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        aapt2ExtractExtraPackagesRule,
+		Description: "aapt2 extract extra packages",
+		Input:       in,
+		Output:      out,
 	})
 }
 
diff --git a/java/aar.go b/java/aar.go
index a682e3a..0216196 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -23,13 +23,13 @@
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/dexpreopt"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
 type AndroidLibraryDependency interface {
-	LibraryDependency
 	ExportPackage() android.Path
 	ResourcesNodeDepSet() *android.DepSet[*resourcesNode]
 	RRODirsDepSet() *android.DepSet[rroDir]
@@ -88,28 +88,40 @@
 	// do not include AndroidManifest from dependent libraries
 	Dont_merge_manifests *bool
 
+	// If use_resource_processor is set, use Bazel's resource processor instead of aapt2 to generate R.class files.
+	// The resource processor produces more optimal R.class files that only list resources in the package of the
+	// library that provided them, as opposed to aapt2 which produces R.java files for every package containing
+	// every resource.  Using the resource processor can provide significant build time speedups, but requires
+	// fixing the module to use the correct package to reference each resource, and to avoid having any other
+	// libraries in the tree that use the same package name.  Defaults to false, but will default to true in the
+	// future.
+	Use_resource_processor *bool
+
 	// true if RRO is enforced for any of the dependent modules
 	RROEnforcedForDependent bool `blueprint:"mutated"`
 }
 
 type aapt struct {
-	aaptSrcJar             android.Path
-	exportPackage          android.Path
-	manifestPath           android.Path
-	proguardOptionsFile    android.Path
-	rTxt                   android.Path
-	extraAaptPackagesFile  android.Path
-	mergedManifestFile     android.Path
-	noticeFile             android.OptionalPath
-	assetPackage           android.OptionalPath
-	isLibrary              bool
-	defaultManifestVersion string
-	useEmbeddedNativeLibs  bool
-	useEmbeddedDex         bool
-	usesNonSdkApis         bool
-	hasNoCode              bool
-	LoggingParent          string
-	resourceFiles          android.Paths
+	aaptSrcJar                     android.Path
+	transitiveAaptRJars            android.Paths
+	transitiveAaptResourcePackages android.Paths
+	exportPackage                  android.Path
+	manifestPath                   android.Path
+	proguardOptionsFile            android.Path
+	rTxt                           android.Path
+	rJar                           android.Path
+	extraAaptPackagesFile          android.Path
+	mergedManifestFile             android.Path
+	noticeFile                     android.OptionalPath
+	assetPackage                   android.OptionalPath
+	isLibrary                      bool
+	defaultManifestVersion         string
+	useEmbeddedNativeLibs          bool
+	useEmbeddedDex                 bool
+	usesNonSdkApis                 bool
+	hasNoCode                      bool
+	LoggingParent                  string
+	resourceFiles                  android.Paths
 
 	splitNames []string
 	splits     []split
@@ -139,6 +151,10 @@
 	}
 }
 
+func (a *aapt) useResourceProcessorBusyBox() bool {
+	return BoolDefault(a.aaptProperties.Use_resource_processor, false)
+}
+
 func (a *aapt) ExportPackage() android.Path {
 	return a.exportPackage
 }
@@ -175,8 +191,6 @@
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
-	linkFlags = append(linkFlags, "--no-static-lib-packages")
-
 	// Find implicit or explicit asset and resource dirs
 	assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets")
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
@@ -348,13 +362,26 @@
 		linkFlags = append(linkFlags, "--static-lib")
 	}
 
+	if a.isLibrary && a.useResourceProcessorBusyBox() {
+		// When building an android_library using ResourceProcessorBusyBox the resources are merged into
+		// package-res.apk with --merge-only, but --no-static-lib-packages is not used so that R.txt only
+		// contains resources from this library.
+		linkFlags = append(linkFlags, "--merge-only")
+	} else {
+		// When building and app or when building an android_library without ResourceProcessorBusyBox
+		// --no-static-lib-packages is used to put all the resources into the app.  If ResourceProcessorBusyBox
+		// is used then the app's R.txt will be post-processed along with the R.txt files from dependencies to
+		// sort resources into the right packages in R.class.
+		linkFlags = append(linkFlags, "--no-static-lib-packages")
+	}
+
 	packageRes := android.PathForModuleOut(ctx, "package-res.apk")
-	// the subdir "android" is required to be filtered by package names
-	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
 	rTxt := android.PathForModuleOut(ctx, "R.txt")
 	// This file isn't used by Soong, but is generated for exporting
 	extraPackages := android.PathForModuleOut(ctx, "extra_packages")
+	var transitiveRJars android.Paths
+	var srcJar android.WritablePath
 
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
@@ -374,7 +401,23 @@
 	// of transitiveStaticLibs.
 	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
 
-	compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+	if a.isLibrary && a.useResourceProcessorBusyBox() {
+		// When building an android_library with ResourceProcessorBusyBox enabled treat static library dependencies
+		// as imports.  The resources from dependencies will not be merged into this module's package-res.apk, and
+		// instead modules depending on this module will reference package-res.apk from all transitive static
+		// dependencies.
+		for _, staticDep := range staticDeps {
+			linkDeps = append(linkDeps, staticDep.resPackage)
+			linkFlags = append(linkFlags, "-I "+staticDep.resPackage.String())
+			if staticDep.usedResourceProcessor {
+				transitiveRJars = append(transitiveRJars, staticDep.rJar)
+			}
+		}
+	} else {
+		// When building an app or building a library without ResourceProcessorBusyBox enabled all static
+		// dependencies are compiled into this module's package-res.apk as overlays.
+		compiledOverlay = append(compiledOverlay, transitiveStaticLibs...)
+	}
 
 	if len(transitiveStaticLibs) > 0 {
 		// If we are using static android libraries, every source file becomes an overlay.
@@ -415,15 +458,19 @@
 		})
 	}
 
+	if !a.useResourceProcessorBusyBox() {
+		// the subdir "android" is required to be filtered by package names
+		srcJar = android.PathForModuleGen(ctx, "android", "R.srcjar")
+	}
+
 	// No need to specify assets from dependencies to aapt2Link for libraries, all transitive assets will be
 	// provided to the final app aapt2Link step.
 	var transitiveAssets android.Paths
 	if !a.isLibrary {
 		transitiveAssets = android.ReverseSliceInPlace(staticDeps.assets())
 	}
-	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt, extraPackages,
+	aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile, rTxt,
 		linkFlags, linkDeps, compiledRes, compiledOverlay, transitiveAssets, splitPackages)
-
 	// Extract assets from the resource package output so that they can be used later in aapt2link
 	// for modules that depend on this one.
 	if android.PrefixInList(linkFlags, "-A ") {
@@ -437,7 +484,19 @@
 		a.assetPackage = android.OptionalPathForPath(assets)
 	}
 
+	if a.useResourceProcessorBusyBox() {
+		rJar := android.PathForModuleOut(ctx, "busybox/R.jar")
+		resourceProcessorBusyBoxGenerateBinaryR(ctx, rTxt, a.mergedManifestFile, rJar, staticDeps, a.isLibrary)
+		aapt2ExtractExtraPackages(ctx, extraPackages, rJar)
+		transitiveRJars = append(transitiveRJars, rJar)
+		a.rJar = rJar
+	} else {
+		aapt2ExtractExtraPackages(ctx, extraPackages, srcJar)
+	}
+
 	a.aaptSrcJar = srcJar
+	a.transitiveAaptRJars = transitiveRJars
+	a.transitiveAaptResourcePackages = staticDeps.resPackages()
 	a.exportPackage = packageRes
 	a.manifestPath = manifestPath
 	a.proguardOptionsFile = proguardOptionsFile
@@ -449,7 +508,11 @@
 			resPackage:          a.exportPackage,
 			manifest:            a.manifestPath,
 			additionalManifests: additionalManifests,
+			rTxt:                a.rTxt,
+			rJar:                a.rJar,
 			assets:              a.assetPackage,
+
+			usedResourceProcessor: a.useResourceProcessorBusyBox(),
 		}).
 		Transitive(staticResourcesNodesDepSet).Build()
 	a.rroDirsDepSet = android.NewDepSetBuilder[rroDir](android.TOPOLOGICAL).
@@ -461,34 +524,93 @@
 		Transitive(staticManifestsDepSet).Build()
 }
 
+var resourceProcessorBusyBox = pctx.AndroidStaticRule("resourceProcessorBusyBox",
+	blueprint.RuleParams{
+		Command: "${config.JavaCmd} -cp ${config.ResourceProcessorBusyBox} " +
+			"com.google.devtools.build.android.ResourceProcessorBusyBox --tool=GENERATE_BINARY_R -- @${out}.args && " +
+			"if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out}; fi",
+		CommandDeps:    []string{"${config.ResourceProcessorBusyBox}"},
+		Rspfile:        "${out}.args",
+		RspfileContent: "--primaryRTxt ${rTxt} --primaryManifest ${manifest} --classJarOutput ${out}.tmp ${args}",
+		Restat:         true,
+	}, "rTxt", "manifest", "args")
+
+// resourceProcessorBusyBoxGenerateBinaryR converts the R.txt file produced by aapt2 into R.class files
+// using Bazel's ResourceProcessorBusyBox tool, which is faster than compiling the R.java files and
+// supports producing classes for static dependencies that only include resources from that dependency.
+func resourceProcessorBusyBoxGenerateBinaryR(ctx android.ModuleContext, rTxt, manifest android.Path,
+	rJar android.WritablePath, transitiveDeps transitiveAarDeps, isLibrary bool) {
+
+	var args []string
+	var deps android.Paths
+
+	if !isLibrary {
+		// When compiling an app, pass all R.txt and AndroidManifest.xml from transitive static library dependencies
+		// to ResourceProcessorBusyBox so that it can regenerate R.class files with the final resource IDs for each
+		// package.
+		args, deps = transitiveDeps.resourceProcessorDeps()
+	} else {
+		// When compiling a library don't pass any dependencies as it only needs to generate an R.class file for this
+		// library.  Pass --finalFields=false so that the R.class file contains non-final fields so they don't get
+		// inlined into the library before the final IDs are assigned during app compilation.
+		args = append(args, "--finalFields=false")
+	}
+
+	deps = append(deps, rTxt, manifest)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        resourceProcessorBusyBox,
+		Output:      rJar,
+		Implicits:   deps,
+		Description: "ResourceProcessorBusyBox",
+		Args: map[string]string{
+			"rTxt":     rTxt.String(),
+			"manifest": manifest.String(),
+			"args":     strings.Join(args, " "),
+		},
+	})
+}
+
 type resourcesNode struct {
 	resPackage          android.Path
 	manifest            android.Path
 	additionalManifests android.Paths
+	rTxt                android.Path
+	rJar                android.Path
 	assets              android.OptionalPath
+
+	usedResourceProcessor bool
 }
 
 type transitiveAarDeps []*resourcesNode
 
 func (t transitiveAarDeps) resPackages() android.Paths {
-	var paths android.Paths
+	paths := make(android.Paths, 0, len(t))
 	for _, dep := range t {
 		paths = append(paths, dep.resPackage)
 	}
-	return android.FirstUniquePaths(paths)
+	return paths
 }
 
 func (t transitiveAarDeps) manifests() android.Paths {
-	var paths android.Paths
+	paths := make(android.Paths, 0, len(t))
 	for _, dep := range t {
 		paths = append(paths, dep.manifest)
 		paths = append(paths, dep.additionalManifests...)
 	}
-	return android.FirstUniquePaths(paths)
+	return paths
+}
+
+func (t transitiveAarDeps) resourceProcessorDeps() (args []string, deps android.Paths) {
+	for _, dep := range t {
+		args = append(args, "--library="+dep.rTxt.String()+","+dep.manifest.String())
+		deps = append(deps, dep.rTxt, dep.manifest)
+	}
+	return args, deps
 }
 
 func (t transitiveAarDeps) assets() android.Paths {
-	var paths android.Paths
+	paths := make(android.Paths, 0, len(t))
 	for _, dep := range t {
 		if dep.assets.Valid() {
 			paths = append(paths, dep.assets.Path())
@@ -613,9 +735,13 @@
 
 	a.stem = proptools.StringDefault(a.overridableDeviceProperties.Stem, ctx.ModuleName())
 
-	ctx.CheckbuildFile(a.proguardOptionsFile)
-	ctx.CheckbuildFile(a.exportPackage)
-	ctx.CheckbuildFile(a.aaptSrcJar)
+	ctx.CheckbuildFile(a.aapt.proguardOptionsFile)
+	ctx.CheckbuildFile(a.aapt.exportPackage)
+	if a.useResourceProcessorBusyBox() {
+		ctx.CheckbuildFile(a.aapt.rJar)
+	} else {
+		ctx.CheckbuildFile(a.aapt.aaptSrcJar)
+	}
 
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
@@ -627,7 +753,22 @@
 	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
 		a.proguardOptionsFile)
 
-	a.Module.compile(ctx, a.aaptSrcJar)
+	var extraSrcJars android.Paths
+	var extraCombinedJars android.Paths
+	var extraClasspathJars android.Paths
+	if a.useResourceProcessorBusyBox() {
+		// When building a library with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox for this
+		// library and each of the transitive static android_library dependencies has already created an
+		// R.class file for the appropriate package.  Add all of those R.class files to the classpath.
+		extraClasspathJars = a.transitiveAaptRJars
+	} else {
+		// When building a library without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+		// R.java files for the library's package and the packages from all transitive static android_library
+		// dependencies.  Compile the srcjar alongside the rest of the sources.
+		extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+	}
+
+	a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
 
 	a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar")
 	var res android.Paths
@@ -636,17 +777,9 @@
 		ctx.CheckbuildFile(a.aarFile)
 	}
 
-	a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files)...)
-
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			if lib, ok := m.(LibraryDependency); ok {
-				a.exportedProguardFlagFiles = append(a.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-			}
-		}
-	})
-	a.exportedProguardFlagFiles = android.FirstUniquePaths(a.exportedProguardFlagFiles)
+	proguardSpecInfo := a.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 
 	prebuiltJniPackages := android.Paths{}
 	ctx.VisitDirectDeps(func(module android.Module) {
@@ -729,12 +862,15 @@
 
 	properties AARImportProperties
 
-	classpathFile         android.WritablePath
-	proguardFlags         android.WritablePath
-	exportPackage         android.WritablePath
-	extraAaptPackagesFile android.WritablePath
-	manifest              android.WritablePath
-	assetsPackage         android.WritablePath
+	classpathFile                  android.WritablePath
+	proguardFlags                  android.WritablePath
+	exportPackage                  android.WritablePath
+	transitiveAaptResourcePackages android.Paths
+	extraAaptPackagesFile          android.WritablePath
+	manifest                       android.WritablePath
+	assetsPackage                  android.WritablePath
+	rTxt                           android.WritablePath
+	rJar                           android.WritablePath
 
 	resourcesNodesDepSet *android.DepSet[*resourcesNode]
 	manifestsDepSet      *android.DepSet[android.Path]
@@ -794,10 +930,6 @@
 func (a *AARImport) ExportPackage() android.Path {
 	return a.exportPackage
 }
-func (a *AARImport) ExportedProguardFlagFiles() android.Paths {
-	return android.Paths{a.proguardFlags}
-}
-
 func (a *AARImport) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.resourcesNodesDepSet
 }
@@ -901,14 +1033,22 @@
 
 	extractedAARDir := android.PathForModuleOut(ctx, "aar")
 	a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
-	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
 	a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
+	aarRTxt := extractedAARDir.Join(ctx, "R.txt")
 	a.assetsPackage = android.PathForModuleOut(ctx, "assets.zip")
+	a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
+	ctx.SetProvider(ProguardSpecInfoProvider, ProguardSpecInfo{
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			android.Paths{a.proguardFlags},
+			nil,
+		),
+	})
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        unzipAAR,
 		Input:       a.aarPath,
-		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage},
+		Outputs:     android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest, a.assetsPackage, aarRTxt},
 		Description: "unzip AAR",
 		Args: map[string]string{
 			"outDir":             extractedAARDir.String(),
@@ -925,17 +1065,15 @@
 	aapt2CompileZip(ctx, flata, a.aarPath, "res", compileFlags)
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
-	// the subdir "android" is required to be filtered by package names
-	srcJar := android.PathForModuleGen(ctx, "android", "R.srcjar")
 	proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
-	rTxt := android.PathForModuleOut(ctx, "R.txt")
+	a.rTxt = android.PathForModuleOut(ctx, "R.txt")
 	a.extraAaptPackagesFile = android.PathForModuleOut(ctx, "extra_packages")
 
 	var linkDeps android.Paths
 
 	linkFlags := []string{
 		"--static-lib",
-		"--no-static-lib-packages",
+		"--merge-only",
 		"--auto-add-overlay",
 	}
 
@@ -948,25 +1086,37 @@
 	_ = staticRRODirsDepSet
 	staticDeps := transitiveAarDeps(staticResourcesNodesDepSet.ToList())
 
-	// AAPT2 overlays are in lowest to highest priority order, reverse the topological order
-	// of transitiveStaticLibs.
-	transitiveStaticLibs := android.ReversePaths(staticDeps.resPackages())
-
 	linkDeps = append(linkDeps, sharedLibs...)
-	linkDeps = append(linkDeps, transitiveStaticLibs...)
+	linkDeps = append(linkDeps, staticDeps.resPackages()...)
 	linkFlags = append(linkFlags, libFlags...)
 
-	overlayRes := append(android.Paths{flata}, transitiveStaticLibs...)
+	overlayRes := android.Paths{flata}
+
+	// Treat static library dependencies of static libraries as imports.
+	transitiveStaticLibs := staticDeps.resPackages()
+	linkDeps = append(linkDeps, transitiveStaticLibs...)
+	for _, staticLib := range transitiveStaticLibs {
+		linkFlags = append(linkFlags, "-I "+staticLib.String())
+	}
 
 	transitiveAssets := android.ReverseSliceInPlace(staticDeps.assets())
-	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
+	aapt2Link(ctx, a.exportPackage, nil, proguardOptionsFile, a.rTxt,
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
 
+	a.rJar = android.PathForModuleOut(ctx, "busybox/R.jar")
+	resourceProcessorBusyBoxGenerateBinaryR(ctx, a.rTxt, a.manifest, a.rJar, nil, true)
+
+	aapt2ExtractExtraPackages(ctx, a.extraAaptPackagesFile, a.rJar)
+
 	resourcesNodesDepSetBuilder := android.NewDepSetBuilder[*resourcesNode](android.TOPOLOGICAL)
 	resourcesNodesDepSetBuilder.Direct(&resourcesNode{
 		resPackage: a.exportPackage,
 		manifest:   a.manifest,
+		rTxt:       a.rTxt,
+		rJar:       a.rJar,
 		assets:     android.OptionalPathForPath(a.assetsPackage),
+
+		usedResourceProcessor: true,
 	})
 	resourcesNodesDepSetBuilder.Transitive(staticResourcesNodesDepSet)
 	a.resourcesNodesDepSet = resourcesNodesDepSetBuilder.Build()
@@ -981,6 +1131,8 @@
 	_ = staticManifestsDepSet
 	a.manifestsDepSet = manifestDepSetBuilder.Build()
 
+	a.transitiveAaptResourcePackages = staticDeps.resPackages()
+
 	a.collectTransitiveHeaderJars(ctx)
 	ctx.SetProvider(JavaInfoProvider, JavaInfo{
 		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
@@ -1071,6 +1223,8 @@
 type bazelAapt struct {
 	Manifest       bazel.Label
 	Resource_files bazel.LabelListAttribute
+	Assets_dir     bazel.StringAttribute
+	Assets         bazel.LabelListAttribute
 }
 
 type bazelAndroidLibrary struct {
@@ -1085,7 +1239,7 @@
 	Sdk_version bazel.StringAttribute
 }
 
-func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) *bazelAapt {
+func (a *aapt) convertAaptAttrsWithBp2Build(ctx android.TopDownMutatorContext) (*bazelAapt, bool) {
 	manifest := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
 
 	resourceFiles := bazel.LabelList{
@@ -1095,10 +1249,30 @@
 		files := android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir))
 		resourceFiles.Includes = append(resourceFiles.Includes, files...)
 	}
+
+	assetsDir := bazel.StringAttribute{}
+	var assets bazel.LabelList
+	for i, dir := range android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") {
+		if i > 0 {
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "multiple asset_dirs")
+			return &bazelAapt{}, false
+		}
+		// Assets_dirs are relative to the module dir when specified, but if the default in used in
+		// PathsWithOptionalDefaultForModuleSrc, then dir is relative to the top.
+		assetsRelDir, error := filepath.Rel(ctx.ModuleDir(), dir.Rel())
+		if error != nil {
+			assetsRelDir = dir.Rel()
+		}
+		assetsDir.Value = proptools.StringPtr(assetsRelDir)
+		assets = bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, androidResourceGlob(ctx, dir)))
+
+	}
 	return &bazelAapt{
 		android.BazelLabelForModuleSrcSingle(ctx, manifest),
 		bazel.MakeLabelListAttribute(resourceFiles),
-	}
+		assetsDir,
+		bazel.MakeLabelListAttribute(assets),
+	}, true
 }
 
 func (a *AARImport) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
@@ -1155,7 +1329,11 @@
 }
 
 func (a *AndroidLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	commonAttrs, bp2buildInfo := a.convertLibraryAttrsBp2Build(ctx)
+	commonAttrs, bp2buildInfo, supported := a.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
+
 	depLabels := bp2buildInfo.DepLabels
 
 	deps := depLabels.Deps
@@ -1167,6 +1345,10 @@
 	name := a.Name()
 	props := AndroidLibraryBazelTargetModuleProperties()
 
+	aaptAttrs, supported := a.convertAaptAttrsWithBp2Build(ctx)
+	if !supported {
+		return
+	}
 	ctx.CreateBazelTargetModule(
 		props,
 		android.CommonAttributes{Name: name},
@@ -1176,7 +1358,7 @@
 				Deps:                 deps,
 				Exports:              depLabels.StaticDeps,
 			},
-			a.convertAaptAttrsWithBp2Build(ctx),
+			aaptAttrs,
 		},
 	)
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 36271dd..b7e2d2f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -79,6 +79,9 @@
 	} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
 		// Platform variant.  If not available for the platform, we don't need Make module.
 		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
+	} else if library.properties.Headers_only {
+		// If generating headers only then don't expose to Make.
+		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
 	} else {
 		entriesList = append(entriesList, android.AndroidMkEntries{
 			Class:      "JAVA_LIBRARIES",
@@ -269,6 +272,7 @@
 				entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile)
 				entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile)
 				entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage)
+				entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages)
 				entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags)
 				entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile)
 				entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest)
@@ -521,6 +525,7 @@
 		}
 
 		entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage)
+		entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages)
 		entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile)
 		entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile)
 		entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...)
diff --git a/java/app.go b/java/app.go
index f1992c9..7ee0e38 100755
--- a/java/app.go
+++ b/java/app.go
@@ -29,6 +29,7 @@
 	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
+	"android/soong/genrule"
 	"android/soong/tradefed"
 )
 
@@ -200,10 +201,6 @@
 	return Bool(a.properties.Installable)
 }
 
-func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
-	return nil
-}
-
 func (a *AndroidApp) ResourcesNodeDepSet() *android.DepSet[*resourcesNode] {
 	return a.aapt.resourcesNodesDepSet
 }
@@ -319,6 +316,17 @@
 	a.generateJavaUsedByApex(ctx)
 }
 
+func (a *AndroidApp) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
+	defaultMinSdkVersion := a.Module.MinSdkVersion(ctx)
+	if proptools.Bool(a.appProperties.Updatable) {
+		overrideApiLevel := android.MinSdkVersionFromValue(ctx, ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride())
+		if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(defaultMinSdkVersion) > 0 {
+			return overrideApiLevel
+		}
+	}
+	return defaultMinSdkVersion
+}
+
 func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
 	if a.Updatable() {
 		if !a.SdkVersion(ctx).Stable() {
@@ -482,8 +490,10 @@
 func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) {
 	var staticLibProguardFlagFiles android.Paths
 	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
+		depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+		staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...)
+		if ctx.OtherModuleDependencyTag(m) == staticLibTag {
+			staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.ProguardFlagsFiles.ToList()...)
 		}
 	})
 
@@ -521,7 +531,23 @@
 	a.dexpreopter.preventInstall = a.appProperties.PreventInstall
 
 	if ctx.ModuleName() != "framework-res" {
-		a.Module.compile(ctx, a.aaptSrcJar)
+		var extraSrcJars android.Paths
+		var extraClasspathJars android.Paths
+		var extraCombinedJars android.Paths
+		if a.useResourceProcessorBusyBox() {
+			// When building an app with ResourceProcessorBusyBox enabled ResourceProcessorBusyBox has already
+			// created R.class files that provide IDs for resources in busybox/R.jar.  Pass that file in the
+			// classpath when compiling everything else, and add it to the final classes jar.
+			extraClasspathJars = android.Paths{a.aapt.rJar}
+			extraCombinedJars = android.Paths{a.aapt.rJar}
+		} else {
+			// When building an app without ResourceProcessorBusyBox the aapt2 rule creates R.srcjar containing
+			// R.java files for the app's package and the packages from all transitive static android_library
+			// dependencies.  Compile the srcjar alongside the rest of the sources.
+			extraSrcJars = android.Paths{a.aapt.aaptSrcJar}
+		}
+
+		a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
 	}
 
 	return a.dexJarFile.PathOrNil()
@@ -1006,7 +1032,13 @@
 	case ".aapt.proguardOptionsFile":
 		return []android.Path{a.proguardOptionsFile}, nil
 	case ".aapt.srcjar":
-		return []android.Path{a.aaptSrcJar}, nil
+		if a.aaptSrcJar != nil {
+			return []android.Path{a.aaptSrcJar}, nil
+		}
+	case ".aapt.jar":
+		if a.rJar != nil {
+			return []android.Path{a.rJar}, nil
+		}
 	case ".export-package.apk":
 		return []android.Path{a.exportPackage}, nil
 	}
@@ -1594,18 +1626,16 @@
 	Certificate      bazel.LabelAttribute
 	Certificate_name bazel.StringAttribute
 	Manifest_values  *manifestValueAttribute
+	Optimize         *bool
+	Proguard_specs   bazel.LabelListAttribute
 }
 
 // ConvertWithBp2build is used to convert android_app to Bazel.
 func (a *AndroidApp) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	commonAttrs, bp2BuildInfo := a.convertLibraryAttrsBp2Build(ctx)
-	depLabels := bp2BuildInfo.DepLabels
-
-	deps := depLabels.Deps
-	deps.Append(depLabels.StaticDeps)
-
-	aapt := a.convertAaptAttrsWithBp2Build(ctx)
-
+	aapt, supported := a.convertAaptAttrsWithBp2Build(ctx)
+	if !supported {
+		return
+	}
 	certificate, certificateName := android.BazelStringOrLabelFromProp(ctx, a.overridableAppProperties.Certificate)
 
 	manifestValues := &manifestValueAttribute{}
@@ -1640,6 +1670,49 @@
 		Manifest_values:  manifestValues,
 	}
 
+	if !BoolDefault(a.dexProperties.Optimize.Enabled, true) {
+		appAttrs.Optimize = proptools.BoolPtr(false)
+	} else {
+		handCraftedFlags := ""
+		if Bool(a.dexProperties.Optimize.Ignore_warnings) {
+			handCraftedFlags += "-ignorewarning "
+		}
+		if !Bool(a.dexProperties.Optimize.Shrink) {
+			handCraftedFlags += "-dontshrink "
+		}
+		if !Bool(a.dexProperties.Optimize.Optimize) {
+			handCraftedFlags += "-dontoptimize "
+		}
+		if !Bool(a.dexProperties.Optimize.Obfuscate) {
+			handCraftedFlags += "-dontobfuscate "
+		}
+		appAttrs.Proguard_specs = bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, a.dexProperties.Optimize.Proguard_flags_files))
+		if handCraftedFlags != "" {
+			generatedFlagFileRuleName := a.Name() + "_proguard_flags"
+			ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
+				Rule_class: "genrule",
+			}, android.CommonAttributes{
+				Name:     generatedFlagFileRuleName,
+				SkipData: proptools.BoolPtr(true),
+			}, &genrule.BazelGenruleAttributes{
+				Outs: []string{a.Name() + "_proguard.flags"},
+				Cmd: bazel.StringAttribute{
+					Value: proptools.StringPtr("echo " + handCraftedFlags + "> $(OUTS)"),
+				},
+			})
+			appAttrs.Proguard_specs.Add(bazel.MakeLabelAttribute(":" + generatedFlagFileRuleName))
+		}
+	}
+
+	commonAttrs, bp2BuildInfo, supported := a.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
+	depLabels := bp2BuildInfo.DepLabels
+
+	deps := depLabels.Deps
+	deps.Append(depLabels.StaticDeps)
+
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        "android_binary",
 		Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
diff --git a/java/app_builder.go b/java/app_builder.go
index d20a6bf..d397ff7 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -225,8 +225,6 @@
 	})
 }
 
-const jniJarOutputPathString = "jniJarOutput.zip"
-
 func TransformJniLibsToJar(
 	ctx android.ModuleContext,
 	outputFile android.WritablePath,
@@ -258,7 +256,10 @@
 		rule = zipRE
 		args["implicits"] = strings.Join(deps.Strings(), ",")
 	}
-	jniJarPath := android.PathForModuleOut(ctx, jniJarOutputPathString)
+	var jniJarPath android.WritablePath = android.PathForModuleOut(ctx, "jniJarOutput.zip")
+	if len(prebuiltJniPackages) == 0 {
+		jniJarPath = outputFile
+	}
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        rule,
 		Description: "zip jni libs",
@@ -266,12 +267,26 @@
 		Implicits:   deps,
 		Args:        args,
 	})
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        mergeAssetsRule,
-		Description: "merge prebuilt JNI packages",
-		Inputs:      append(prebuiltJniPackages, jniJarPath),
-		Output:      outputFile,
-	})
+	if len(prebuiltJniPackages) > 0 {
+		var mergeJniJarPath android.WritablePath = android.PathForModuleOut(ctx, "mergeJniJarOutput.zip")
+		if !uncompressJNI {
+			mergeJniJarPath = outputFile
+		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        mergeAssetsRule,
+			Description: "merge prebuilt JNI packages",
+			Inputs:      append(prebuiltJniPackages, jniJarPath),
+			Output:      mergeJniJarPath,
+		})
+
+		if uncompressJNI {
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   uncompressEmbeddedJniLibsRule,
+				Input:  mergeJniJarPath,
+				Output: outputFile,
+			})
+		}
+	}
 }
 
 func (a *AndroidApp) generateJavaUsedByApex(ctx android.ModuleContext) {
diff --git a/java/app_import.go b/java/app_import.go
index ad1765e..1718d93 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -277,6 +277,14 @@
 		a.hideApexVariantFromMake = true
 	}
 
+	if Bool(a.properties.Preprocessed) {
+		if a.properties.Presigned != nil && !*a.properties.Presigned {
+			ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false")
+		}
+		t := true
+		a.properties.Presigned = &t
+	}
+
 	numCertPropsSet := 0
 	if String(a.properties.Certificate) != "" {
 		numCertPropsSet++
@@ -288,11 +296,9 @@
 		numCertPropsSet++
 	}
 	if numCertPropsSet != 1 {
-		ctx.ModuleErrorf("One and only one of certficate, presigned, and default_dev_cert properties must be set")
+		ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set")
 	}
 
-	_, _, certificates := collectAppDeps(ctx, a, false, false)
-
 	// TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK
 	// TODO: LOCAL_PACKAGE_SPLITS
 
@@ -365,6 +371,7 @@
 	} else if !Bool(a.properties.Presigned) {
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
 		// Which makes processMainCert's behavior for the empty cert string WAI.
+		_, _, certificates := collectAppDeps(ctx, a, false, false)
 		a.certificate, certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
 		signed := android.PathForModuleOut(ctx, "signed", apkFilename)
 		var lineageFile android.Path
@@ -377,8 +384,13 @@
 		SignAppPackage(ctx, signed, jnisUncompressed, certificates, nil, lineageFile, rotationMinSdkVersion)
 		a.outputFile = signed
 	} else {
+		// Presigned without Preprocessed shouldn't really be a thing, currently we disallow
+		// it for apps with targetSdk >= 30, because on those targetSdks you must be using signature
+		// v2 or later, and signature v2 would be wrecked by uncompressing libs / zipaligning.
+		// But ideally we would disallow it for all prebuilt apks, and remove the presigned property.
+		targetSdkCheck := a.validateTargetSdkLessThan30(ctx, srcApk)
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
-		TransformZipAlign(ctx, alignedApk, jnisUncompressed)
+		TransformZipAlign(ctx, alignedApk, jnisUncompressed, []android.Path{targetSdkCheck})
 		a.outputFile = alignedApk
 		a.certificate = PresignedCertificate
 	}
@@ -432,6 +444,16 @@
 	})
 }
 
+func (a *AndroidAppImport) validateTargetSdkLessThan30(ctx android.ModuleContext, srcApk android.Path) android.Path {
+	alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "old_target_sdk.stamp")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   checkBelowTargetSdk30ForNonPreprocessedApks,
+		Input:  srcApk,
+		Output: alignmentStamp,
+	})
+	return alignmentStamp
+}
+
 func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
 	return &a.prebuilt
 }
diff --git a/java/app_import_test.go b/java/app_import_test.go
index bb8fab9..506c734 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -629,31 +629,21 @@
 			presigned: true,
 			preprocessed: true,
 		}
-
-		android_test_import {
-			name: "foo_cert",
-			apk: "prebuilts/apk/app.apk",
-			certificate: "cert/new_cert",
-			preprocessed: true,
-		}
 		`)
 
-	testModules := []string{"foo", "foo_cert"}
-	for _, m := range testModules {
-		apkName := m + ".apk"
-		variant := ctx.ModuleForTests(m, "android_common")
-		jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
-		if jniRule != android.Cp.String() {
-			t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
-		}
+	apkName := "foo.apk"
+	variant := ctx.ModuleForTests("foo", "android_common")
+	jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
+	if jniRule != android.Cp.String() {
+		t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+	}
 
-		// Make sure signing and aligning were skipped.
-		if variant.MaybeOutput("signed/"+apkName).Rule != nil {
-			t.Errorf("signing rule shouldn't be included for preprocessed.")
-		}
-		if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
-			t.Errorf("aligning rule shouldn't be for preprocessed")
-		}
+	// Make sure signing and aligning were skipped.
+	if variant.MaybeOutput("signed/"+apkName).Rule != nil {
+		t.Errorf("signing rule shouldn't be included for preprocessed.")
+	}
+	if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
+		t.Errorf("aligning rule shouldn't be for preprocessed")
 	}
 }
 
diff --git a/java/app_test.go b/java/app_test.go
index c438b6c..fc57f44 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -722,7 +722,10 @@
 
 func TestAndroidResourceProcessor(t *testing.T) {
 	testCases := []struct {
-		name string
+		name                string
+		appUsesRP           bool
+		directLibUsesRP     bool
+		transitiveLibUsesRP bool
 
 		dontVerifyApp bool
 		appResources  []string
@@ -759,7 +762,12 @@
 		transitiveImportImports    []string
 	}{
 		{
-			name: "legacy",
+			// Test with all modules set to use_resource_processor: false (except android_library_import modules,
+			// which always use resource processor).
+			name:                "legacy",
+			appUsesRP:           false,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: false,
 
 			appResources: nil,
 			appOverlays: []string{
@@ -771,7 +779,6 @@
 				"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"},
 			appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"},
 			appClasspath: []string{
@@ -792,7 +799,6 @@
 				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
 				"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
 			},
-
 			directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
 			directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
 			directClasspath: []string{
@@ -814,18 +820,256 @@
 			transitiveCombined:  nil,
 
 			directImportResources: nil,
-			directImportOverlays: []string{
-				"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata",
+			directImportOverlays:  []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
+			directImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
 				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
 			},
-			directImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
 
 			transitiveImportResources: nil,
-			transitiveImportOverlays: []string{
-				"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata",
+			transitiveImportOverlays:  []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+			transitiveImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
 				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
 			},
-			transitiveImportImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+		},
+		{
+			// Test with all modules set to use_resource_processor: true.
+			name:                "resource_processor",
+			appUsesRP:           true,
+			directLibUsesRP:     true,
+			transitiveLibUsesRP: true,
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
+				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+			},
+			appImports: []string{"out/soong/.intermediates/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/direct/android_common/turbine-combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+
+			directResources: nil,
+			directOverlays:  []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+			directImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+			},
+			directSrcJars: nil,
+			directClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+				"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+			directCombined: []string{
+				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
+				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   nil,
+			transitiveClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+			},
+			transitiveCombined: nil,
+
+			directImportResources: nil,
+			directImportOverlays:  []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"},
+			directImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+			},
+
+			transitiveImportResources: nil,
+			transitiveImportOverlays:  []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"},
+			transitiveImportImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+			},
+		}, {
+			// Test an app building with resource processor enabled but with dependencies built without
+			// resource processor.
+			name:                "app_resource_processor",
+			appUsesRP:           true,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: false,
+
+			appResources: nil,
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
+				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+			},
+			appImports: []string{"out/soong/.intermediates/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/direct/android_common/turbine-combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/busybox/R.jar",
+				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+
+			dontVerifyDirect:           true,
+			dontVerifyTransitive:       true,
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
+		},
+		{
+			// Test an app building without resource processor enabled but with a dependency built with
+			// resource processor.
+			name:                "app_dependency_lib_resource_processor",
+			appUsesRP:           false,
+			directLibUsesRP:     true,
+			transitiveLibUsesRP: false,
+
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
+				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+			},
+			appImports: []string{"out/soong/.intermediates/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/direct/android_common/turbine-combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+
+			directResources: nil,
+			directOverlays:  []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"},
+			directImports: []string{
+				"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+			},
+			directSrcJars: nil,
+			directClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive_import/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar",
+				"out/soong/.intermediates/direct/android_common/busybox/R.jar",
+				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+			directCombined: []string{
+				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
+				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+
+			dontVerifyTransitive:       true,
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
+		},
+		{
+			// Test a library building without resource processor enabled but with a dependency built with
+			// resource processor.
+			name:                "lib_dependency_lib_resource_processor",
+			appUsesRP:           false,
+			directLibUsesRP:     false,
+			transitiveLibUsesRP: true,
+
+			appOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/direct_import/android_common/package-res.apk",
+				"out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat",
+			},
+			appImports: []string{"out/soong/.intermediates/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/direct/android_common/turbine-combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+			appCombined: []string{
+				"out/soong/.intermediates/app/android_common/javac/app.jar",
+				"out/soong/.intermediates/direct/android_common/combined/direct.jar",
+				"out/soong/.intermediates/direct_import/android_common/aar/classes-combined.jar",
+			},
+
+			directResources: nil,
+			directOverlays: []string{
+				"out/soong/.intermediates/transitive/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk",
+				"out/soong/.intermediates/transitive_import/android_common/package-res.apk",
+				"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat",
+			},
+			directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"},
+			directClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+			directCombined: []string{
+				"out/soong/.intermediates/direct/android_common/javac/direct.jar",
+				"out/soong/.intermediates/transitive/android_common/javac/transitive.jar",
+				"out/soong/.intermediates/transitive_import/android_common/aar/classes-combined.jar",
+			},
+
+			transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"},
+			transitiveOverlays:  nil,
+			transitiveImports:   []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"},
+			transitiveSrcJars:   nil,
+			transitiveClasspath: []string{
+				"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar",
+				"out/soong/.intermediates/transitive/android_common/busybox/R.jar",
+			},
+			transitiveCombined: nil,
+
+			dontVerifyDirectImport:     true,
+			dontVerifyTransitiveImport: true,
 		},
 	}
 
@@ -839,6 +1083,7 @@
 					resource_dirs: ["app/res"],
 					manifest: "app/AndroidManifest.xml",
 					static_libs: ["direct", "direct_import"],
+					use_resource_processor: %v,
 				}
 
 				android_library {
@@ -848,6 +1093,7 @@
 					resource_dirs: ["direct/res"],
 					manifest: "direct/AndroidManifest.xml",
 					static_libs: ["transitive", "transitive_import"],
+					use_resource_processor: %v,
 				}
 
 				android_library {
@@ -856,6 +1102,7 @@
 					srcs: ["transitive/transitive.java"],
 					resource_dirs: ["transitive/res"],
 					manifest: "transitive/AndroidManifest.xml",
+					use_resource_processor: %v,
 				}
 
 				android_library_import {
@@ -883,7 +1130,7 @@
 					sdk_version: "current",
 					aars: ["transitive_import_dep.aar"],
 				}
-			`)
+			`, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP)
 
 			fs := android.MockFS{
 				"app/res/values/strings.xml":        nil,
@@ -1495,7 +1742,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output(jniJarOutputPathString)
+			jniLibZip := app.Output("jnilibs.zip")
 			var abis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -1628,7 +1875,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
 			if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
 				t.Errorf("expected jni packaged %v, got %v", w, g)
 			}
@@ -1719,7 +1966,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
 
-			jniLibZip := app.MaybeOutput(jniJarOutputPathString)
+			jniLibZip := app.MaybeOutput("jnilibs.zip")
 			if len(jniLibZip.Implicits) != 1 {
 				t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings())
 			}
@@ -2739,7 +2986,7 @@
 	for _, test := range testCases {
 		t.Run(test.name, func(t *testing.T) {
 			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output(jniJarOutputPathString)
+			jniLibZip := app.Output("jnilibs.zip")
 			var jnis []string
 			args := strings.Fields(jniLibZip.Args["jarArgs"])
 			for i := 0; i < len(args); i++ {
@@ -3890,3 +4137,49 @@
 		"\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml",
 	)
 }
+
+func TestApexGlobalMinSdkVersionOverride(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.ApexGlobalMinSdkVersionOverride = proptools.StringPtr("Tiramisu")
+		}),
+	).RunTestWithBp(t, `
+		android_app {
+			name: "com.android.bar",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+		android_app {
+			name: "com.android.foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+			min_sdk_version: "S",
+			updatable: true,
+		}
+		override_android_app {
+			name: "com.android.go.foo",
+			base: "com.android.foo",
+		}
+	`)
+	foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer")
+	fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer")
+	bar := result.ModuleForTests("com.android.bar", "android_common").Rule("manifestFixer")
+
+	android.AssertStringDoesContain(t,
+		"expected manifest fixer to set com.android.bar minSdkVersion to S",
+		bar.BuildParams.Args["args"],
+		"--minSdkVersion  S",
+	)
+	android.AssertStringDoesContain(t,
+		"com.android.foo: expected manifest fixer to set minSdkVersion to T",
+		foo.BuildParams.Args["args"],
+		"--minSdkVersion  T",
+	)
+	android.AssertStringDoesContain(t,
+		"com.android.go.foo: expected manifest fixer to set minSdkVersion to T",
+		fooOverride.BuildParams.Args["args"],
+		"--minSdkVersion  T",
+	)
+
+}
diff --git a/java/base.go b/java/base.go
index 2293f64..8f48398 100644
--- a/java/base.go
+++ b/java/base.go
@@ -192,6 +192,9 @@
 
 	// Additional srcJars tacked in by GeneratedJavaLibraryModule
 	Generated_srcjars []android.Path `android:"mutated"`
+
+	// If true, then only the headers are built and not the implementation jar.
+	Headers_only bool
 }
 
 // Properties that are specific to device modules. Host module factories should not add these when
@@ -574,6 +577,17 @@
 	}
 }
 
+func (j *Module) checkHeadersOnly(ctx android.ModuleContext) {
+	if _, ok := ctx.Module().(android.SdkContext); ok {
+		headersOnly := proptools.Bool(&j.properties.Headers_only)
+		installable := proptools.Bool(j.properties.Installable)
+
+		if headersOnly && installable {
+			ctx.PropertyErrorf("headers_only", "This module has conflicting settings. headers_only is true which, which means this module doesn't generate an implementation jar. However installable is set to true.")
+		}
+	}
+}
+
 func (j *Module) addHostProperties() {
 	j.AddProperties(
 		&j.properties,
@@ -622,6 +636,8 @@
 			return android.Paths{j.dexer.proguardDictionary.Path()}, nil
 		}
 		return nil, fmt.Errorf("%q was requested, but no output file was found.", tag)
+	case ".generated_srcjars":
+		return j.properties.Generated_srcjars, nil
 	default:
 		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
 	}
@@ -1065,7 +1081,7 @@
 	module.properties.Generated_srcjars = append(module.properties.Generated_srcjars, path)
 }
 
-func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
+func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars android.Paths) {
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
 	deps := j.collectDeps(ctx)
@@ -1103,9 +1119,7 @@
 
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
-	if aaptSrcJar != nil {
-		srcJars = append(srcJars, aaptSrcJar)
-	}
+	srcJars = append(srcJars, extraSrcJars...)
 	srcJars = append(srcJars, j.properties.Generated_srcjars...)
 	srcFiles = srcFiles.FilterOutByExt(".srcjar")
 
@@ -1148,6 +1162,41 @@
 	var kotlinJars android.Paths
 	var kotlinHeaderJars android.Paths
 
+	// Prepend extraClasspathJars to classpath so that the resource processor R.jar comes before
+	// any dependencies so that it can override any non-final R classes from dependencies with the
+	// final R classes from the app.
+	flags.classpath = append(android.CopyOf(extraClasspathJars), flags.classpath...)
+
+	// If compiling headers then compile them and skip the rest
+	if j.properties.Headers_only {
+		if srcFiles.HasExt(".kt") {
+			ctx.ModuleErrorf("Compiling headers_only with .kt not supported")
+		}
+		if ctx.Config().IsEnvFalse("TURBINE_ENABLED") || disableTurbine {
+			ctx.ModuleErrorf("headers_only is enabled but Turbine is disabled.")
+		}
+
+		_, j.headerJarFile =
+			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName,
+				extraCombinedJars)
+		if ctx.Failed() {
+			return
+		}
+
+		ctx.SetProvider(JavaInfoProvider, JavaInfo{
+			HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
+			TransitiveLibsHeaderJars:       j.transitiveLibsHeaderJars,
+			TransitiveStaticLibsHeaderJars: j.transitiveStaticLibsHeaderJars,
+			AidlIncludeDirs:                j.exportAidlIncludeDirs,
+			ExportedPlugins:                j.exportedPluginJars,
+			ExportedPluginClasses:          j.exportedPluginClasses,
+			ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
+		})
+
+		j.outputFile = j.headerJarFile
+		return
+	}
+
 	if srcFiles.HasExt(".kt") {
 		// When using kotlin sources turbine is used to generate annotation processor sources,
 		// including for annotation processors that generate API, so we can use turbine for
@@ -1241,8 +1290,9 @@
 			// allow for the use of annotation processors that do function correctly
 			// with sharding enabled. See: b/77284273.
 		}
+		extraJars := append(android.CopyOf(extraCombinedJars), kotlinHeaderJars...)
 		headerJarFileWithoutDepsOrJarjar, j.headerJarFile =
-			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, kotlinHeaderJars)
+			j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars)
 		if ctx.Failed() {
 			return
 		}
@@ -1393,6 +1443,8 @@
 		jars = append(jars, servicesJar)
 	}
 
+	jars = append(android.CopyOf(extraCombinedJars), jars...)
+
 	// Combine the classes built from sources, any manifests, and any static libraries into
 	// classes.jar. If there is only one input jar this step will be skipped.
 	var outputFile android.OutputPath
@@ -1556,7 +1608,7 @@
 					false, nil, nil)
 				if *j.dexProperties.Uncompress_dex {
 					combinedAlignedJar := android.PathForModuleOut(ctx, "dex-withres-aligned", jarName).OutputPath
-					TransformZipAlign(ctx, combinedAlignedJar, combinedJar)
+					TransformZipAlign(ctx, combinedAlignedJar, combinedJar, nil)
 					dexOutputFile = combinedAlignedJar
 				} else {
 					dexOutputFile = combinedJar
@@ -1664,6 +1716,49 @@
 	return android.InList("androidx.compose.runtime_runtime", j.properties.Static_libs)
 }
 
+func (j *Module) collectProguardSpecInfo(ctx android.ModuleContext) ProguardSpecInfo {
+	transitiveUnconditionalExportedFlags := []*android.DepSet[android.Path]{}
+	transitiveProguardFlags := []*android.DepSet[android.Path]{}
+
+	ctx.VisitDirectDeps(func(m android.Module) {
+		depProguardInfo := ctx.OtherModuleProvider(m, ProguardSpecInfoProvider).(ProguardSpecInfo)
+		depTag := ctx.OtherModuleDependencyTag(m)
+
+		if depProguardInfo.UnconditionallyExportedProguardFlags != nil {
+			transitiveUnconditionalExportedFlags = append(transitiveUnconditionalExportedFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.UnconditionallyExportedProguardFlags)
+		}
+
+		if depTag == staticLibTag && depProguardInfo.ProguardFlagsFiles != nil {
+			transitiveProguardFlags = append(transitiveProguardFlags, depProguardInfo.ProguardFlagsFiles)
+		}
+	})
+
+	directUnconditionalExportedFlags := android.Paths{}
+	proguardFlagsForThisModule := android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)
+	exportUnconditionally := proptools.Bool(j.dexProperties.Optimize.Export_proguard_flags_files)
+	if exportUnconditionally {
+		// if we explicitly export, then our unconditional exports are the same as our transitive flags
+		transitiveUnconditionalExportedFlags = transitiveProguardFlags
+		directUnconditionalExportedFlags = proguardFlagsForThisModule
+	}
+
+	return ProguardSpecInfo{
+		Export_proguard_flags_files: exportUnconditionally,
+		ProguardFlagsFiles: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			proguardFlagsForThisModule,
+			transitiveProguardFlags,
+		),
+		UnconditionallyExportedProguardFlags: android.NewDepSet[android.Path](
+			android.POSTORDER,
+			directUnconditionalExportedFlags,
+			transitiveUnconditionalExportedFlags,
+		),
+	}
+
+}
+
 // Returns a copy of the supplied flags, but with all the errorprone-related
 // fields copied to the regular build's fields.
 func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags {
diff --git a/java/builder.go b/java/builder.go
index afbd69e..bf91917 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -55,7 +55,7 @@
 				`$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` +
 				`if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` +
 				`if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` +
-				`rm -rf "$srcJarDir"`,
+				`rm -rf "$srcJarDir" "$outDir"`,
 			CommandDeps: []string{
 				"${config.JavacCmd}",
 				"${config.SoongZipCmd}",
@@ -277,6 +277,14 @@
 			Command:     `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`,
 			CommandDeps: []string{"${config.Zip2ZipCmd}"},
 		})
+
+	checkBelowTargetSdk30ForNonPreprocessedApks = pctx.AndroidStaticRule("checkBelowTargetSdk30ForNonPreprocessedApks",
+		blueprint.RuleParams{
+			Command:     "build/soong/scripts/check_target_sdk_less_than_30.py ${config.Aapt2Cmd} $in $out",
+			CommandDeps: []string{"build/soong/scripts/check_target_sdk_less_than_30.py", "${config.Aapt2Cmd}"},
+			Description: "Check prebuilt target sdk version",
+		},
+	)
 )
 
 func init() {
@@ -689,12 +697,13 @@
 	android.WriteFileRule(ctx, outputFile, "Main-Class: "+mainClass+"\n")
 }
 
-func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path) {
+func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePath, inputFile android.Path, validations android.Paths) {
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        zipalign,
 		Description: "align",
 		Input:       inputFile,
 		Output:      outputFile,
+		Validations: validations,
 	})
 }
 
diff --git a/java/config/config.go b/java/config/config.go
index 195dae1..83c27d3 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -148,6 +148,8 @@
 	pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
 	pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
 
+	pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar")
+
 	pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file")
 
 	pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index eadd9c6..4380f4f 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -55,6 +55,19 @@
     ],
 }
 
+java_api_library {
+    name: "core.current.stubs.from-text",
+    api_surface: "core",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "conscrypt.module.public.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+}
+
 java_library {
     name: "core.current.stubs",
     defaults: [
@@ -146,12 +159,42 @@
     ],
 }
 
+java_defaults {
+    name: "core.module_lib.stubs.defaults",
+    visibility: ["//visibility:private"],
+    sdk_version: "none",
+    system_modules: "none",
+}
+
 // A stubs target containing the parts of the public SDK & @SystemApi(MODULE_LIBRARIES) API
 // provided by the core libraries.
 //
 // Don't use this directly, use "sdk_version: module_current".
 java_library {
     name: "core.module_lib.stubs",
+    defaults: [
+        "core.module_lib.stubs.defaults",
+    ],
+    static_libs: [
+        "core.module_lib.stubs.from-source",
+    ],
+    product_variables: {
+        build_from_text_stub: {
+            static_libs: [
+                "core.module_lib.stubs.from-text",
+            ],
+            exclude_static_libs: [
+                "core.module_lib.stubs.from-source",
+            ],
+        },
+    },
+}
+
+java_library {
+    name: "core.module_lib.stubs.from-source",
+    defaults: [
+        "core.module_lib.stubs.defaults",
+    ],
     static_libs: [
         "art.module.public.api.stubs.module_lib",
 
@@ -161,9 +204,6 @@
         "conscrypt.module.public.api.stubs",
         "i18n.module.public.api.stubs",
     ],
-    sdk_version: "none",
-    system_modules: "none",
-    visibility: ["//visibility:private"],
 }
 
 // Produces a dist file that is used by the
@@ -237,6 +277,32 @@
     ],
 }
 
+java_defaults {
+    name: "android_core_platform_stubs_current_contributions",
+    api_surface: "core_platform",
+    api_contributions: [
+        "art.module.public.api.stubs.source.api.contribution",
+        "art.module.public.api.stubs.source.system.api.contribution",
+        "art.module.public.api.stubs.source.module_lib.api.contribution",
+        "conscrypt.module.platform.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
+    ],
+}
+
+java_api_library {
+    name: "legacy.core.platform.api.stubs.from-text",
+    api_surface: "core_platform",
+    defaults: [
+        "android_core_platform_stubs_current_contributions",
+    ],
+    api_contributions: [
+        "legacy.i18n.module.platform.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+}
+
 java_library {
     name: "legacy.core.platform.api.stubs",
     visibility: core_platform_visibility,
@@ -249,10 +315,10 @@
     product_variables: {
         build_from_text_stub: {
             static_libs: [
-                "stable.core.platform.api.stubs.from-text",
+                "legacy.core.platform.api.stubs.from-text",
             ],
             exclude_static_libs: [
-                "stable.core.platform.api.stubs.from-source",
+                "legacy.core.platform.api.stubs.from-source",
             ],
         },
     },
@@ -300,6 +366,20 @@
     ],
 }
 
+java_api_library {
+    name: "stable.core.platform.api.stubs.from-text",
+    api_surface: "core_platform",
+    defaults: [
+        "android_core_platform_stubs_current_contributions",
+    ],
+    api_contributions: [
+        "stable.i18n.module.platform.api.stubs.source.api.contribution",
+    ],
+    libs: [
+        "stub-annotations",
+    ],
+}
+
 java_library {
     name: "stable.core.platform.api.stubs",
     visibility: core_platform_visibility,
diff --git a/java/core-libraries/TxtStubLibraries.bp b/java/core-libraries/TxtStubLibraries.bp
index 0cf0f36..c46f8b8 100644
--- a/java/core-libraries/TxtStubLibraries.bp
+++ b/java/core-libraries/TxtStubLibraries.bp
@@ -57,19 +57,23 @@
     ],
 }
 
-java_library {
+java_api_library {
     name: "core.module_lib.stubs.from-text",
-    static_libs: [
-        "art.module.public.api.stubs.module_lib.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",
 
-        // Replace the following with the module-lib correspondence when Conscrypt or i18N module
+        // 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.from-text",
-        "i18n.module.public.api.stubs.from-text",
+        "conscrypt.module.public.api.stubs.source.api.contribution",
+        "i18n.module.public.api.stubs.source.api.contribution",
     ],
-    sdk_version: "none",
-    system_modules: "none",
+    libs: [
+        "stub-annotations",
+    ],
     visibility: ["//visibility:private"],
 }
 
diff --git a/java/dex.go b/java/dex.go
index 7dd14bd..5b8cf3d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -71,6 +71,10 @@
 
 		// Specifies the locations of files containing proguard flags.
 		Proguard_flags_files []string `android:"path"`
+
+		// If true, transitive reverse dependencies of this module will have this
+		// module's proguard spec appended to their optimization action
+		Export_proguard_flags_files *bool
 	}
 
 	// Keep the data uncompressed. We always need uncompressed dex for execution,
@@ -213,8 +217,9 @@
 	// Note: Targets with a min SDK kind of core_platform (e.g., framework.jar) or unspecified (e.g.,
 	// services.jar), are not classified as stable, which is WAI.
 	// TODO(b/232073181): Expand to additional min SDK cases after validation.
+	var addAndroidPlatformBuildFlag = false
 	if !dexParams.sdkVersion.Stable() {
-		flags = append(flags, "--android-platform-build")
+		addAndroidPlatformBuildFlag = true
 	}
 
 	effectiveVersion, err := dexParams.minSdkVersion.EffectiveVersion(ctx)
@@ -222,7 +227,18 @@
 		ctx.PropertyErrorf("min_sdk_version", "%s", err)
 	}
 
-	flags = append(flags, "--min-api "+strconv.Itoa(effectiveVersion.FinalOrFutureInt()))
+	// If the specified SDK level is 10000, then configure the compiler to use the
+	// current platform SDK level and to compile the build as a platform build.
+	var minApiFlagValue = effectiveVersion.FinalOrFutureInt()
+	if minApiFlagValue == 10000 {
+		minApiFlagValue = ctx.Config().PlatformSdkVersion().FinalInt()
+		addAndroidPlatformBuildFlag = true
+	}
+	flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue))
+
+	if addAndroidPlatformBuildFlag {
+		flags = append(flags, "--android-platform-build")
+	}
 	return flags, deps
 }
 
@@ -434,7 +450,7 @@
 	}
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath
-		TransformZipAlign(ctx, alignedJavalibJar, javalibJar)
+		TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil)
 		javalibJar = alignedJavalibJar
 	}
 
diff --git a/java/dex_test.go b/java/dex_test.go
index 2ba3831..ec1ef15 100644
--- a/java/dex_test.go
+++ b/java/dex_test.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"testing"
 
 	"android/soong/android"
@@ -327,7 +328,7 @@
 		fooD8.Args["d8Flags"], staticLibHeader.String())
 }
 
-func TestProguardFlagsInheritance(t *testing.T) {
+func TestProguardFlagsInheritanceStatic(t *testing.T) {
 	result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, `
 		android_app {
 			name: "app",
@@ -380,3 +381,246 @@
 	android.AssertStringDoesContain(t, "expected tertiary_lib's proguard flags from inherited dep",
 		appR8.Args["r8Flags"], "tertiary.flags")
 }
+
+func TestProguardFlagsInheritance(t *testing.T) {
+	directDepFlagsFileName := "direct_dep.flags"
+	transitiveDepFlagsFileName := "transitive_dep.flags"
+	bp := `
+		android_app {
+			name: "app",
+			static_libs: ["androidlib"], // this must be static_libs to initate dexing
+			platform_apis: true,
+		}
+
+		android_library {
+			name: "androidlib",
+			static_libs: ["app_dep"],
+		}
+
+		java_library {
+			name: "app_dep",
+			%s: ["dep"],
+		}
+
+		java_library {
+			name: "dep",
+			%s: ["transitive_dep"],
+			optimize: {
+				proguard_flags_files: ["direct_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+
+		java_library {
+			name: "transitive_dep",
+			optimize: {
+				proguard_flags_files: ["transitive_dep.flags"],
+				export_proguard_flags_files: %v,
+			},
+		}
+	`
+
+	testcases := []struct {
+		name                           string
+		depType                        string
+		depExportsFlagsFiles           bool
+		transitiveDepType              string
+		transitiveDepExportsFlagsFiles bool
+		expectedFlagsFiles             []string
+	}{
+		{
+			name:                           "libs_export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_no-export_libs_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: true,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "libs_no-export_libs_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{},
+		},
+		{
+			name:                           "static_no-export_libs_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           false,
+			transitiveDepType:              "libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName},
+		},
+		{
+			name:                           "libs_export_static_no-export",
+			depType:                        "libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+		{
+			name:                           "static_export_static_no-export",
+			depType:                        "static_libs",
+			depExportsFlagsFiles:           true,
+			transitiveDepType:              "static_libs",
+			transitiveDepExportsFlagsFiles: false,
+			expectedFlagsFiles:             []string{directDepFlagsFileName, transitiveDepFlagsFileName},
+		},
+	}
+
+	for _, 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")
+
+			shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles)
+			if shouldHaveDepFlags {
+				android.AssertStringDoesContain(t, "expected deps's proguard flags",
+					appR8.Args["r8Flags"], directDepFlagsFileName)
+			} else {
+				android.AssertStringDoesNotContain(t, "app did not expect deps's proguard flags",
+					appR8.Args["r8Flags"], directDepFlagsFileName)
+			}
+
+			shouldHaveTransitiveDepFlags := android.InList(transitiveDepFlagsFileName, tc.expectedFlagsFiles)
+			if shouldHaveTransitiveDepFlags {
+				android.AssertStringDoesContain(t, "expected transitive deps's proguard flags",
+					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+			} else {
+				android.AssertStringDoesNotContain(t, "app did not expect transitive deps's proguard flags",
+					appR8.Args["r8Flags"], transitiveDepFlagsFileName)
+			}
+		})
+	}
+}
+
+func TestProguardFlagsInheritanceAppImport(t *testing.T) {
+	bp := `
+		android_app {
+			name: "app",
+			static_libs: ["aarimport"], // this must be static_libs to initate dexing
+			platform_apis: true,
+		}
+
+		android_library {
+			name: "androidlib",
+			static_libs: ["aarimport"],
+		}
+
+		android_library_import {
+			name: "aarimport",
+			aars: ["import.aar"],
+		}
+	`
+	result := android.GroupFixturePreparers(
+		PrepareForTestWithJavaDefaultModules,
+	).RunTestWithBp(t, bp)
+
+	appR8 := result.ModuleForTests("app", "android_common").Rule("r8")
+	android.AssertStringDoesContain(t, "expected aarimports's proguard flags",
+		appR8.Args["r8Flags"], "proguard.txt")
+}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d4ead12..3ba3065 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -699,7 +699,6 @@
 	cmd := rule.Command().
 		BuiltTool("soong_javac_wrapper").Tool(config.JavadocCmd(ctx)).
 		Flag(config.JavacVmFlags).
-		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "javadoc.rsp"), srcs).
 		FlagWithInput("@", srcJarList)
 
diff --git a/java/droidstubs.go b/java/droidstubs.go
index bb2388f..f05ef1f 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -512,17 +512,16 @@
 	cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
 		Flag(config.JavacVmFlags).
 		Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
-		FlagWithArg("-encoding ", "UTF-8").
-		FlagWithArg("-source ", javaVersion.String()).
+		FlagWithArg("--java-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", android.PathForModuleOut(ctx, "metalava.rsp"), srcs).
 		FlagWithInput("@", srcJarList)
 
-	if len(bootclasspath) > 0 {
-		cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
-	}
-
-	if len(classpath) > 0 {
-		cmd.FlagWithInputList("-classpath ", classpath.Paths(), ":")
+	// Metalava does not differentiate between bootclasspath and classpath and has not done so for
+	// years, so it is unlikely to change any time soon.
+	combinedPaths := append(([]android.Path)(nil), bootclasspath.Paths()...)
+	combinedPaths = append(combinedPaths, classpath.Paths()...)
+	if len(combinedPaths) > 0 {
+		cmd.FlagWithInputList("--classpath ", combinedPaths, ":")
 	}
 
 	cmd.Flag("--color").
@@ -695,6 +694,13 @@
 		cmd.FlagWithArg("--error-message:compatibility:released ", msg)
 	}
 
+	if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
+		// Pass the current API file into metalava so it can use it as the basis for determining how to
+		// generate the output signature files (both api and removed).
+		currentApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
+		cmd.FlagWithInput("--use-same-format-as ", currentApiFile)
+	}
+
 	if generateStubs {
 		rule.Command().
 			BuiltTool("soong_zip").
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index f9baa85..578237e 100644
--- a/java/generated_java_library.go
+++ b/java/generated_java_library.go
@@ -22,6 +22,10 @@
 	Library
 	callbacks  GeneratedJavaLibraryCallbacks
 	moduleName string
+
+	// true if we've already called DepsMutator. Can't call AddLibrary or AddSharedLibrary
+	// after DepsMutator.
+	depsMutatorDone bool
 }
 
 type GeneratedJavaLibraryCallbacks interface {
@@ -59,8 +63,25 @@
 	return module
 }
 
+// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
+func (module *GeneratedJavaLibraryModule) AddSharedLibrary(name string) {
+	if module.depsMutatorDone {
+		panic("GeneratedJavaLibraryModule.AddLibrary called after DepsMutator")
+	}
+	module.Library.properties.Libs = append(module.Library.properties.Libs, name)
+}
+
+// Add a java shared library as a dependency, as if they had said `libs: [ "name" ]`
+func (module *GeneratedJavaLibraryModule) AddStaticLibrary(name string) {
+	if module.depsMutatorDone {
+		panic("GeneratedJavaLibraryModule.AddStaticLibrary called after DepsMutator")
+	}
+	module.Library.properties.Static_libs = append(module.Library.properties.Static_libs, name)
+}
+
 func (module *GeneratedJavaLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) {
 	module.callbacks.DepsMutator(module, ctx)
+	module.depsMutatorDone = true
 	module.Library.DepsMutator(ctx)
 }
 
@@ -78,11 +99,6 @@
 	checkPropertyEmpty(ctx, module, "exclude_srcs", module.Library.properties.Exclude_srcs)
 	checkPropertyEmpty(ctx, module, "java_resource_dirs", module.Library.properties.Java_resource_dirs)
 	checkPropertyEmpty(ctx, module, "exclude_java_resource_dirs", module.Library.properties.Exclude_java_resource_dirs)
-	// No additional libraries. The generator should add anything necessary automatically
-	// by returning something from ____ (TODO: Additional libraries aren't needed now, so
-	// these are just blocked).
-	checkPropertyEmpty(ctx, module, "libs", module.Library.properties.Libs)
-	checkPropertyEmpty(ctx, module, "static_libs", module.Library.properties.Static_libs)
 	// Restrict these for no good reason other than to limit the surface area. If there's a
 	// good use case put them back.
 	checkPropertyEmpty(ctx, module, "plugins", module.Library.properties.Plugins)
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index d25096b..fe3fe7b 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -106,7 +106,7 @@
 	h.uncompressDexState = uncompressedDexState
 
 	// If hiddenapi processing is disabled treat this as inactive.
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
@@ -305,7 +305,7 @@
 	})
 
 	if uncompressDex {
-		TransformZipAlign(ctx, output, encodeRuleOutput)
+		TransformZipAlign(ctx, output, encodeRuleOutput, nil)
 	}
 
 	return output
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 714634f..8ec1797 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -121,8 +121,8 @@
 
 // hiddenAPI singleton rules
 func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
-	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	// Don't run any hiddenapi rules if hiddenapi checks are disabled
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
diff --git a/java/java.go b/java/java.go
index 20d9afc..99bb1b3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,11 +21,13 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
 	"android/soong/remoteexec"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -224,6 +226,23 @@
 	}, "jar_name", "partition", "main_class")
 )
 
+type ProguardSpecInfo struct {
+	// If true, proguard flags files will be exported to reverse dependencies across libs edges
+	// If false, proguard flags files will only be exported to reverse dependencies across
+	// static_libs edges.
+	Export_proguard_flags_files bool
+
+	// TransitiveDepsProguardSpecFiles is a depset of paths to proguard flags files that are exported from
+	// all transitive deps. This list includes all proguard flags files from transitive static dependencies,
+	// and all proguard flags files from transitive libs dependencies which set `export_proguard_spec: true`.
+	ProguardFlagsFiles *android.DepSet[android.Path]
+
+	// implementation detail to store transitive proguard flags files from exporting shared deps
+	UnconditionallyExportedProguardFlags *android.DepSet[android.Path]
+}
+
+var ProguardSpecInfoProvider = blueprint.NewProvider(ProguardSpecInfo{})
+
 // JavaInfo contains information about a java module for use by modules that depend on it.
 type JavaInfo struct {
 	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
@@ -309,11 +328,6 @@
 	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 }
 
-// Provides transitive Proguard flag files to downstream DEX jars.
-type LibraryDependency interface {
-	ExportedProguardFlagFiles() android.Paths
-}
-
 // TODO(jungjw): Move this to kythe.go once it's created.
 type xref interface {
 	XrefJavaFiles() android.Paths
@@ -625,12 +639,6 @@
 	InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
 }
 
-var _ LibraryDependency = (*Library)(nil)
-
-func (j *Library) ExportedProguardFlagFiles() android.Paths {
-	return j.exportedProguardFlagFiles
-}
-
 var _ android.ApexModule = (*Library)(nil)
 
 // Provides access to the list of permitted packages from apex boot jars.
@@ -691,6 +699,7 @@
 	}
 
 	j.checkSdkVersions(ctx)
+	j.checkHeadersOnly(ctx)
 	if ctx.Device() {
 		j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
 			ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
@@ -699,7 +708,7 @@
 		j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
 		j.classLoaderContexts = j.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
 	}
-	j.compile(ctx, nil)
+	j.compile(ctx, nil, nil, nil)
 
 	// Collect the module directory for IDE info in java/jdeps.go.
 	j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
@@ -729,15 +738,9 @@
 		j.installFile = ctx.InstallFile(installDir, j.Stem()+".jar", j.outputFile, extraInstallDeps...)
 	}
 
-	j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles,
-		android.PathsForModuleSrc(ctx, j.dexProperties.Optimize.Proguard_flags_files)...)
-	ctx.VisitDirectDeps(func(m android.Module) {
-		if lib, ok := m.(LibraryDependency); ok && ctx.OtherModuleDependencyTag(m) == staticLibTag {
-			j.exportedProguardFlagFiles = append(j.exportedProguardFlagFiles, lib.ExportedProguardFlagFiles()...)
-		}
-	})
-	j.exportedProguardFlagFiles = android.FirstUniquePaths(j.exportedProguardFlagFiles)
-
+	proguardSpecInfo := j.collectProguardSpecInfo(ctx)
+	ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo)
+	j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList()
 }
 
 func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1682,6 +1685,9 @@
 	// extracting the compiled class files provided by the
 	// full_api_surface_stub module.
 	Full_api_surface_stub *string
+
+	// Version of previously released API file for compatibility check.
+	Previous_api *string `android:"path"`
 }
 
 func ApiLibraryFactory() android.Module {
@@ -1725,12 +1731,10 @@
 	cmd.BuiltTool("metalava").ImplicitTool(ctx.Config().HostJavaToolPath(ctx, "metalava.jar")).
 		Flag(config.JavacVmFlags).
 		Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
-		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithInputList("--source-files ", srcs, " ")
 
 	cmd.Flag("--color").
 		Flag("--quiet").
-		Flag("--format=v2").
 		Flag("--include-annotations").
 		// The flag makes nullability issues as warnings rather than errors by replacing
 		// @Nullable/@NonNull in the listed packages APIs with @RecentlyNullable/@RecentlyNonNull,
@@ -1742,14 +1746,13 @@
 		FlagWithArg("--hide ", "InvalidNullabilityOverride").
 		FlagWithArg("--hide ", "ChangedDefault")
 
-	// Force metalava to ignore classes on the classpath when an API file contains missing classes.
-	// See b/285140653 for more information.
+	// 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")
 
-	// Force metalava to sort overloaded methods by their order in the source code.
-	// See b/285312164 for more information.
-	cmd.FlagWithArg("--api-overloaded-method-order ", "source")
-
 	return cmd
 }
 
@@ -1812,6 +1815,28 @@
 	}
 }
 
+// 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" })
+
+func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFiles android.Paths) android.Paths {
+	sortedSrcFiles := android.Paths{}
+
+	for _, scopeSourceFileName := range scopeOrderedSourceFileNames {
+		for _, sourceFileName := range srcFiles {
+			if sourceFileName.Base() == scopeSourceFileName {
+				sortedSrcFiles = append(sortedSrcFiles, sourceFileName)
+			}
+		}
+	}
+	if len(srcFiles) != len(sortedSrcFiles) {
+		ctx.ModuleErrorf("Unrecognizable source file found within %s", srcFiles)
+	}
+
+	return sortedSrcFiles
+}
+
 func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 
 	rule := android.NewRuleBuilder(pctx, ctx)
@@ -1862,10 +1887,18 @@
 		ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
 	}
 
+	srcFiles = al.sortApiFilesByApiScope(ctx, srcFiles)
+
 	cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir)
 
 	al.stubsFlags(ctx, cmd, stubsDir)
 
+	migratingNullability := String(al.properties.Previous_api) != ""
+	if migratingNullability {
+		previousApi := android.PathForModuleSrc(ctx, String(al.properties.Previous_api))
+		cmd.FlagWithInput("--migrate-nullness ", previousApi)
+	}
+
 	al.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()))
@@ -1881,7 +1914,7 @@
 		FlagWithArg("-C ", stubsDir.String()).
 		FlagWithArg("-D ", stubsDir.String())
 
-	rule.Build("metalava", "metalava merged")
+	rule.Build("metalava", "metalava merged text")
 
 	if depApiSrcsStubsJar == nil {
 		var flags javaBuilderFlags
@@ -2722,32 +2755,41 @@
 type javaResourcesAttributes struct {
 	Resources             bazel.LabelListAttribute
 	Resource_strip_prefix *string
+	Additional_resources  bazel.LabelListAttribute
 }
 
-func (m *Library) javaResourcesGetSingleFilegroupStripPrefix(ctx android.TopDownMutatorContext) (string, bool) {
-	if otherM, ok := ctx.ModuleFromName(m.properties.Java_resources[0]); ok && len(m.properties.Java_resources) == 1 {
+func (m *Library) getResourceFilegroupStripPrefix(ctx android.TopDownMutatorContext, resourceFilegroup string) (*string, bool) {
+	if otherM, ok := ctx.ModuleFromName(resourceFilegroup); ok {
 		if fg, isFilegroup := otherM.(android.FileGroupPath); isFilegroup {
-			return filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx)), true
+			return proptools.StringPtr(filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx))), true
 		}
 	}
-	return "", false
+	return proptools.StringPtr(""), false
 }
 
 func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes {
 	var resources bazel.LabelList
 	var resourceStripPrefix *string
 
-	if m.properties.Java_resources != nil && len(m.properties.Java_resource_dirs) > 0 {
-		ctx.ModuleErrorf("bp2build doesn't support both java_resources and java_resource_dirs being set on the same module.")
-	}
+	additionalJavaResourcesMap := make(map[string]*javaResourcesAttributes)
 
 	if m.properties.Java_resources != nil {
-		if prefix, ok := m.javaResourcesGetSingleFilegroupStripPrefix(ctx); ok {
-			resourceStripPrefix = proptools.StringPtr(prefix)
-		} else {
+		for _, res := range m.properties.Java_resources {
+			if prefix, isFilegroup := m.getResourceFilegroupStripPrefix(ctx, res); isFilegroup {
+				otherM, _ := ctx.ModuleFromName(res)
+				resourcesTargetName := ctx.ModuleName() + "_filegroup_resources_" + otherM.Name()
+				additionalJavaResourcesMap[resourcesTargetName] = &javaResourcesAttributes{
+					Resources:             bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{res})),
+					Resource_strip_prefix: prefix,
+				}
+			} else {
+				resources.Append(android.BazelLabelForModuleSrc(ctx, []string{res}))
+			}
+		}
+
+		if !resources.IsEmpty() {
 			resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
 		}
-		resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
 	}
 
 	//TODO(b/179889880) handle case where glob includes files outside package
@@ -2758,23 +2800,51 @@
 		m.properties.Exclude_java_resources,
 	)
 
-	for i, resDep := range resDeps {
+	for _, resDep := range resDeps {
 		dir, files := resDep.dir, resDep.files
 
-		resources.Append(bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, files)))
-
 		// Bazel includes the relative path from the WORKSPACE root when placing the resource
 		// inside the JAR file, so we need to remove that prefix
-		resourceStripPrefix = proptools.StringPtr(dir.String())
-		if i > 0 {
-			// TODO(b/226423379) allow multiple resource prefixes
-			ctx.ModuleErrorf("bp2build does not support more than one directory in java_resource_dirs (b/226423379)")
+		prefix := proptools.StringPtr(dir.String())
+		resourcesTargetName := ctx.ModuleName() + "_resource_dir_" + dir.String()
+		additionalJavaResourcesMap[resourcesTargetName] = &javaResourcesAttributes{
+			Resources:             bazel.MakeLabelListAttribute(bazel.MakeLabelList(android.RootToModuleRelativePaths(ctx, files))),
+			Resource_strip_prefix: prefix,
 		}
 	}
 
+	var additionalResourceLabels bazel.LabelList
+	if len(additionalJavaResourcesMap) > 0 {
+		var additionalResources []string
+		for resName, _ := range additionalJavaResourcesMap {
+			additionalResources = append(additionalResources, resName)
+		}
+		sort.Strings(additionalResources)
+
+		for i, resName := range additionalResources {
+			resAttr := additionalJavaResourcesMap[resName]
+			if resourceStripPrefix == nil && i == 0 {
+				resourceStripPrefix = resAttr.Resource_strip_prefix
+				resources = resAttr.Resources.Value
+			} else if !resAttr.Resources.IsEmpty() {
+				ctx.CreateBazelTargetModule(
+					bazel.BazelTargetModuleProperties{
+						Rule_class:        "java_resources",
+						Bzl_load_location: "//build/bazel/rules/java:java_resources.bzl",
+					},
+					android.CommonAttributes{Name: resName},
+					resAttr,
+				)
+				additionalResourceLabels.Append(android.BazelLabelForModuleSrc(ctx, []string{resName}))
+			}
+		}
+
+	}
+
 	return &javaResourcesAttributes{
 		Resources:             bazel.MakeLabelListAttribute(resources),
 		Resource_strip_prefix: resourceStripPrefix,
+		Additional_resources:  bazel.MakeLabelListAttribute(additionalResourceLabels),
 	}
 }
 
@@ -2819,12 +2889,8 @@
 	hasKotlin bool
 }
 
-// Replaces //a/b/my_xsd_config with //a/b/my_xsd_config-java
-func xsdConfigJavaTarget(ctx android.BazelConversionPathContext, mod blueprint.Module) string {
-	callback := func(xsd android.XsdConfigBp2buildTargets) string {
-		return xsd.JavaBp2buildTargetName()
-	}
-	return android.XsdConfigBp2buildTarget(ctx, mod, callback)
+func javaXsdTargetName(xsd android.XsdConfigBp2buildTargets) string {
+	return xsd.JavaBp2buildTargetName()
 }
 
 // convertLibraryAttrsBp2Build returns a javaCommonAttributes struct with
@@ -2832,24 +2898,31 @@
 // which has other non-attribute information needed for bp2build conversion
 // that needs different handling depending on the module types, and thus needs
 // to be returned to the calling function.
-func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo) {
+func (m *Library) convertLibraryAttrsBp2Build(ctx android.TopDownMutatorContext) (*javaCommonAttributes, *bp2BuildJavaInfo, bool) {
 	var srcs bazel.LabelListAttribute
 	var deps bazel.LabelListAttribute
-	var staticDeps bazel.LabelList
+	var staticDeps bazel.LabelListAttribute
+
+	if proptools.String(m.deviceProperties.Sdk_version) == "" && m.DeviceSupported() {
+		// TODO(b/297356704): handle platform apis in bp2build
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "sdk_version unset")
+		return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false
+	} else if proptools.String(m.deviceProperties.Sdk_version) == "core_platform" {
+		// TODO(b/297356582): handle core_platform in bp2build
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "sdk_version core_platform")
+		return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false
+	}
 
 	archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
 			if archProps, ok := _props.(*CommonProperties); ok {
-				srcsNonXsd, srcsXsd := android.PartitionXsdSrcs(ctx, archProps.Srcs)
-				excludeSrcsNonXsd, _ := android.PartitionXsdSrcs(ctx, archProps.Exclude_srcs)
-				archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, srcsNonXsd, excludeSrcsNonXsd)
+				archSrcs := android.BazelLabelForModuleSrcExcludes(ctx, archProps.Srcs, archProps.Exclude_srcs)
 				srcs.SetSelectValue(axis, config, archSrcs)
-
-				// Add to static deps
-				xsdJavaConfigLibraryLabels := android.BazelLabelForModuleDepsWithFn(ctx, srcsXsd, xsdConfigJavaTarget)
-				staticDeps.Append(xsdJavaConfigLibraryLabels)
-
+				if archProps.Jarjar_rules != nil {
+					ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "jarjar_rules")
+					return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false
+				}
 			}
 		}
 	}
@@ -2857,6 +2930,7 @@
 
 	javaSrcPartition := "java"
 	protoSrcPartition := "proto"
+	xsdSrcPartition := "xsd"
 	logtagSrcPartition := "logtag"
 	aidlSrcPartition := "aidl"
 	kotlinPartition := "kotlin"
@@ -2865,6 +2939,7 @@
 		logtagSrcPartition: bazel.LabelPartition{Extensions: []string{".logtags", ".logtag"}},
 		protoSrcPartition:  android.ProtoSrcLabelPartition,
 		aidlSrcPartition:   android.AidlSrcLabelPartition,
+		xsdSrcPartition:    bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(javaXsdTargetName)},
 		kotlinPartition:    bazel.LabelPartition{Extensions: []string{".kt"}},
 	})
 
@@ -2872,6 +2947,8 @@
 	kotlinSrcs := srcPartitions[kotlinPartition]
 	javaSrcs.Append(kotlinSrcs)
 
+	staticDeps.Append(srcPartitions[xsdSrcPartition])
+
 	if !srcPartitions[logtagSrcPartition].IsEmpty() {
 		logtagsLibName := m.Name() + "_logtags"
 		ctx.CreateBazelTargetModule(
@@ -2925,7 +3002,7 @@
 			},
 		)
 
-		staticDeps.Add(&bazel.Label{Label: ":" + javaAidlLibName})
+		staticDeps.Append(bazel.MakeSingleLabelListAttribute(bazel.Label{Label: ":" + javaAidlLibName}))
 	}
 
 	var javacopts bazel.StringListAttribute //[]string
@@ -2980,7 +3057,9 @@
 	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
 	// that depend on a java_library with proto sources can link directly to the protobuf API,
 	// and so this should be a static dependency.
-	staticDeps.Add(protoDepLabel)
+	if protoDepLabel != nil {
+		staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
+	}
 
 	depLabels := &javaDependencyLabels{}
 	depLabels.Deps = deps
@@ -2995,7 +3074,7 @@
 			}
 		}
 	}
-	depLabels.StaticDeps.Value.Append(staticDeps)
+	depLabels.StaticDeps.Append(staticDeps)
 
 	hasKotlin := !kotlinSrcs.IsEmpty()
 	commonAttrs.kotlinAttributes = &kotlinAttributes{
@@ -3011,7 +3090,7 @@
 		hasKotlin: hasKotlin,
 	}
 
-	return commonAttrs, bp2BuildInfo
+	return commonAttrs, bp2BuildInfo, true
 }
 
 type javaLibraryAttributes struct {
@@ -3041,7 +3120,10 @@
 }
 
 func javaLibraryBp2Build(ctx android.TopDownMutatorContext, m *Library) {
-	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
+	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
@@ -3088,7 +3170,10 @@
 
 // JavaBinaryHostBp2Build is for java_binary_host bp2build.
 func javaBinaryHostBp2Build(ctx android.TopDownMutatorContext, m *Binary) {
-	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
+	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
@@ -3172,7 +3257,10 @@
 
 // javaTestHostBp2Build is for java_test_host bp2build.
 func javaTestHostBp2Build(ctx android.TopDownMutatorContext, m *TestHost) {
-	commonAttrs, bp2BuildInfo := m.convertLibraryAttrsBp2Build(ctx)
+	commonAttrs, bp2BuildInfo, supported := m.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
diff --git a/java/java_test.go b/java/java_test.go
index dd98677..27933c3 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1864,12 +1864,12 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -1897,11 +1897,11 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt", "api1/current.txt", "api2/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -1918,25 +1918,25 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_c := `
 	java_api_contribution {
 		name: "foo3",
-		api_file: "foo3.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_d := `
 	java_api_contribution {
 		name: "foo4",
-		api_file: "foo4.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -1985,15 +1985,15 @@
 	}{
 		{
 			moduleName:         "bar1",
-			sourceTextFileDirs: []string{"a/foo1.txt"},
+			sourceTextFileDirs: []string{"a/current.txt"},
 		},
 		{
 			moduleName:         "bar2",
-			sourceTextFileDirs: []string{"a/foo1.txt", "b/foo2.txt"},
+			sourceTextFileDirs: []string{"a/current.txt", "b/current.txt"},
 		},
 		{
 			moduleName:         "bar3",
-			sourceTextFileDirs: []string{"c/foo3.txt", "a/foo1.txt", "b/foo2.txt", "d/foo4.txt", "api1/current.txt", "api2/current.txt"},
+			sourceTextFileDirs: []string{"c/current.txt", "a/current.txt", "b/current.txt", "d/current.txt", "api1/current.txt", "api2/current.txt"},
 		},
 	}
 	for _, c := range testcases {
@@ -2010,13 +2010,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	ctx, _ := testJavaWithFS(t, `
@@ -2063,13 +2063,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
@@ -2138,13 +2138,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
@@ -2212,13 +2212,13 @@
 	provider_bp_a := `
 	java_api_contribution {
 		name: "foo1",
-		api_file: "foo1.txt",
+		api_file: "current.txt",
 	}
 	`
 	provider_bp_b := `
 	java_api_contribution {
 		name: "foo2",
-		api_file: "foo2.txt",
+		api_file: "current.txt",
 	}
 	`
 	lib_bp_a := `
@@ -2370,3 +2370,21 @@
 		t.Errorf("Module output does not contain expected jar %s", "test.jar")
 	}
 }
+
+func TestHeadersOnly(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			headers_only: true,
+		}
+	`)
+
+	turbine := ctx.ModuleForTests("foo", "android_common").Rule("turbine")
+	if len(turbine.Inputs) != 1 || turbine.Inputs[0].String() != "a.java" {
+		t.Errorf(`foo inputs %v != ["a.java"]`, turbine.Inputs)
+	}
+
+	javac := ctx.ModuleForTests("foo", "android_common").MaybeRule("javac")
+	android.AssertDeepEquals(t, "javac rule", nil, javac.Rule)
+}
diff --git a/java/kotlin.go b/java/kotlin.go
index f28d6c7..3637e2e 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -42,7 +42,7 @@
 			` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` +
 			`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` +
 			`${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` +
-			`rm -rf "$srcJarDir"`,
+			`rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`,
 		CommandDeps: []string{
 			"${config.KotlincCmd}",
 			"${config.KotlinCompilerJar}",
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 1bb4996..8494d02 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -122,3 +122,17 @@
 --warning_check RemoteViewLayout
 --warning_check SupportAnnotationUsage
 --warning_check UniqueConstants
+
+# TODO(b/294098365): these checks fail in AOSP, but pass downstream
+--warning_check ForegroundServiceType
+--warning_check MutableImplicitPendingIntent
+
+--warning_check ExactAlarm
+--warning_check ExpiredTargetSdkVersion
+--warning_check ForegroundServicePermission
+--warning_check ObsoleteSdkInt
+--warning_check ScheduleExactAlarm
+--warning_check StartActivityAndCollapseDeprecated
+--warning_check UnspecifiedRegisterReceiverFlag
+--warning_check WearMaterialTheme
+--warning_check WearStandaloneAppFlag
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index a4bba48..ade7395 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -113,7 +113,7 @@
 }
 
 func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) {
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		return
 	}
 
@@ -275,10 +275,10 @@
 
 	bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
 
-	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
+	// Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance
 	// optimization that can be used to reduce the incremental build time but as its name suggests it
 	// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
-	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+	if ctx.Config().DisableHiddenApiChecks() {
 		paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
 		for _, path := range paths {
 			ctx.Build(pctx, android.BuildParams{
diff --git a/java/plugin.go b/java/plugin.go
index 731dfda..5127298 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -66,7 +66,10 @@
 // ConvertWithBp2build is used to convert android_app to Bazel.
 func (p *Plugin) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	pluginName := p.Name()
-	commonAttrs, bp2BuildInfo := p.convertLibraryAttrsBp2Build(ctx)
+	commonAttrs, bp2BuildInfo, supported := p.convertLibraryAttrsBp2Build(ctx)
+	if !supported {
+		return
+	}
 	depLabels := bp2BuildInfo.DepLabels
 
 	deps := depLabels.Deps
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 044802e..99cb99b 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -55,6 +55,11 @@
 
 	// If set to true, compile dex for java_import modules. Defaults to false.
 	Imports_compile_dex *bool
+
+	// If set to true, allow incremental platform API of the form MM.m where MM is the major release
+	// version corresponding to the API level/SDK_INT and m is an incremental release version
+	// (e.g. API changes associated with QPR). Defaults to false.
+	Allow_incremental_platform_api *bool
 }
 
 type prebuiltApis struct {
@@ -69,6 +74,8 @@
 // parsePrebuiltPath parses the relevant variables out of a variety of paths, e.g.
 // <version>/<scope>/<module>.jar
 // <version>/<scope>/api/<module>.txt
+// *Note when using incremental platform API, <version> may be of the form MM.m where MM is the
+// API level and m is an incremental release, otherwise <version> is a single integer corresponding to the API level only.
 // extensions/<version>/<scope>/<module>.jar
 // extensions/<version>/<scope>/api/<module>.txt
 func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, version string, scope string) {
@@ -90,8 +97,25 @@
 }
 
 // parseFinalizedPrebuiltPath is like parsePrebuiltPath, but verifies the version is numeric (a finalized version).
-func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string) (module string, version int, scope string) {
+func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string, allowIncremental bool) (module string, version int, release int, scope string) {
 	module, v, scope := parsePrebuiltPath(ctx, p)
+	if allowIncremental {
+		parts := strings.Split(v, ".")
+		if len(parts) != 2 {
+			ctx.ModuleErrorf("Found unexpected version '%v' for incremental prebuilts - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", v)
+			return
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			ctx.ModuleErrorf("Unable to read version number for incremental prebuilt api '%v'", v)
+			return
+		}
+		version = sdk
+		release = qpr
+		return
+	}
+	release = 0
 	version, err := strconv.Atoi(v)
 	if err != nil {
 		ctx.ModuleErrorf("Found finalized API files in non-numeric dir '%v'", v)
@@ -268,29 +292,35 @@
 	}
 
 	// Create modules for all (<module>, <scope, <version>) triplets,
+	allowIncremental := proptools.BoolDefault(p.properties.Allow_incremental_platform_api, false)
 	for _, f := range apiLevelFiles {
-		module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
-		createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
+		if allowIncremental {
+			incrementalVersion := strconv.Itoa(version) + "." + strconv.Itoa(release)
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, incrementalVersion), f)
+		} else {
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		}
 	}
 
 	// Figure out the latest version of each module/scope
 	type latestApiInfo struct {
 		module, scope, path string
-		version             int
+		version, release    int
 		isExtensionApiFile  bool
 	}
 
 	getLatest := func(files []string, isExtensionApiFile bool) map[string]latestApiInfo {
 		m := make(map[string]latestApiInfo)
 		for _, f := range files {
-			module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
+			module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
 			if strings.HasSuffix(module, "incompatibilities") {
 				continue
 			}
 			key := module + "." + scope
 			info, exists := m[key]
-			if !exists || version > info.version {
-				m[key] = latestApiInfo{module, scope, f, version, isExtensionApiFile}
+			if !exists || version > info.version || (version == info.version && release > info.release) {
+				m[key] = latestApiInfo{module, scope, f, version, release, isExtensionApiFile}
 			}
 		}
 		return m
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
index 2b84353..b6fb2c6 100644
--- a/java/prebuilt_apis_test.go
+++ b/java/prebuilt_apis_test.go
@@ -99,3 +99,26 @@
 	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
 	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
 }
+
+func TestPrebuiltApis_WithIncrementalApi(t *testing.T) {
+	runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) {
+		result := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			FixtureWithPrebuiltIncrementalApis(map[string][]string{
+				"33.0":    {"foo"},
+				"33.1":    {"foo", "bar", "baz"},
+				"33.2":    {"foo", "bar"},
+				"current": {"foo", "bar"},
+			}),
+		).RunTest(t)
+		foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
+		bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
+		baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String()
+		return
+	}
+	// 33.1 is the latest for baz, 33.2 is the latest for both foo & bar
+	foo_input, bar_input, baz_input := runTestWithIncrementalApi()
+	android.AssertStringEquals(t, "Expected latest foo = api level 33.2", "prebuilts/sdk/33.2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = api level 33.2", "prebuilts/sdk/33.2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 33.1", "prebuilts/sdk/33.1/public/api/baz.txt", baz_input)
+}
diff --git a/java/proto.go b/java/proto.go
index c732d98..2ed7b27 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -143,7 +143,14 @@
 }
 
 type protoAttributes struct {
-	Deps         bazel.LabelListAttribute
+	Deps bazel.LabelListAttribute
+
+	// A list of proto_library targets that the proto_library in `deps` depends on
+	// This list is overestimation.
+	// Overestimation is necessary since Soong includes other protos via proto.include_dirs and not
+	// a specific .proto file module explicitly.
+	Transitive_deps bazel.LabelListAttribute
+
 	Sdk_version  bazel.StringAttribute
 	Java_version bazel.StringAttribute
 }
@@ -176,11 +183,11 @@
 		ctx.PropertyErrorf("proto.type", "cannot handle conversion at this time: %q", typ)
 	}
 
-	protoLabel := bazel.Label{Label: ":" + m.Name() + "_proto"}
 	protoAttrs := &protoAttributes{
-		Deps:         bazel.MakeSingleLabelListAttribute(protoLabel),
-		Java_version: bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:  bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		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},
 	}
 
 	name := m.Name() + suffix
diff --git a/java/sdk_library.go b/java/sdk_library.go
index dbb2f02..d1620af 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -387,6 +387,23 @@
 		apiScopeModuleLib,
 		apiScopeSystemServer,
 	}
+	apiLibraryAdditionalProperties = map[string]struct {
+		FullApiSurfaceStubLib     string
+		AdditionalApiContribution string
+	}{
+		"legacy.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "legacy.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"stable.i18n.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "i18n.module.public.api.stubs.source.api.contribution",
+		},
+		"conscrypt.module.platform.api": {
+			FullApiSurfaceStubLib:     "stable.core.platform.api.stubs",
+			AdditionalApiContribution: "conscrypt.module.public.api.stubs.source.api.contribution",
+		},
+	}
 )
 
 var (
@@ -1513,6 +1530,29 @@
 	return exists
 }
 
+// The listed modules are the special java_sdk_libraries where apiScope.kind do not match the
+// api surface that the module contribute to. For example, the public droidstubs and java_library
+// do not contribute to the public api surface, but contributes to the core platform api surface.
+// This method returns the full api surface stub lib that
+// the generated java_api_library should depend on.
+func (module *SdkLibrary) alternativeFullApiSurfaceStubLib() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.FullApiSurfaceStubLib
+	}
+	return ""
+}
+
+// The listed modules' stubs contents do not match the corresponding txt files,
+// but require additional api contributions to generate the full stubs.
+// This method returns the name of the additional api contribution module
+// for corresponding sdk_library modules.
+func (module *SdkLibrary) apiLibraryAdditionalApiContribution() string {
+	if val, ok := apiLibraryAdditionalProperties[module.Name()]; ok {
+		return val.AdditionalApiContribution
+	}
+	return ""
+}
+
 func childModuleVisibility(childVisibility []string) []string {
 	if childVisibility == nil {
 		// No child visibility set. The child will use the visibility of the sdk_library.
@@ -1593,7 +1633,7 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.sourceStubLibraryModuleName(apiScope))
-	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 	// sources are generated from the droiddoc
 	props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
 	sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
@@ -1778,7 +1818,7 @@
 	mctx.CreateModule(DroidstubsFactory, &props).(*Droidstubs).CallHookIfAvailable(mctx)
 }
 
-func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
+func (module *SdkLibrary) createApiLibrary(mctx android.DefaultableHookContext, apiScope *apiScope, alternativeFullApiSurfaceStub string) {
 	props := struct {
 		Name                  *string
 		Visibility            []string
@@ -1789,7 +1829,7 @@
 	}{}
 
 	props.Name = proptools.StringPtr(module.apiLibraryModuleName(apiScope))
-	props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility)
+	props.Visibility = []string{"//visibility:override", "//visibility:private"}
 
 	apiContributions := []string{}
 
@@ -1801,13 +1841,22 @@
 		apiContributions = append(apiContributions, module.stubsSourceModuleName(scope)+".api.contribution")
 		scope = scope.extends
 	}
+	if apiScope == apiScopePublic {
+		additionalApiContribution := module.apiLibraryAdditionalApiContribution()
+		if additionalApiContribution != "" {
+			apiContributions = append(apiContributions, additionalApiContribution)
+		}
+	}
 
 	props.Api_contributions = apiContributions
 	props.Libs = module.properties.Libs
 	props.Libs = append(props.Libs, module.sdkLibraryProperties.Stub_only_libs...)
 	props.Libs = append(props.Libs, "stub-annotations")
 	props.Static_libs = module.sdkLibraryProperties.Stub_only_static_libs
-	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName() + ".from-text")
+	props.Full_api_surface_stub = proptools.StringPtr(apiScope.kind.DefaultJavaLibraryName())
+	if alternativeFullApiSurfaceStub != "" {
+		props.Full_api_surface_stub = proptools.StringPtr(alternativeFullApiSurfaceStub)
+	}
 
 	// android_module_lib_stubs_current.from-text only comprises api contributions from art, conscrypt and i18n.
 	// Thus, replace with android_module_lib_stubs_current_full.from-text, which comprises every api domains.
@@ -2062,9 +2111,13 @@
 
 		module.createStubsLibrary(mctx, scope)
 
-		contributesToApiSurface := module.contributesToApiSurface(mctx.Config())
+		alternativeFullApiSurfaceStubLib := ""
+		if scope == apiScopePublic {
+			alternativeFullApiSurfaceStubLib = module.alternativeFullApiSurfaceStubLib()
+		}
+		contributesToApiSurface := module.contributesToApiSurface(mctx.Config()) || alternativeFullApiSurfaceStubLib != ""
 		if contributesToApiSurface {
-			module.createApiLibrary(mctx, scope)
+			module.createApiLibrary(mctx, scope, alternativeFullApiSurfaceStubLib)
 		}
 
 		module.createTopLevelStubsLibrary(mctx, scope, contributesToApiSurface)
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index c22b980..868d697 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -1449,17 +1449,17 @@
 		{
 			scope:              apiScopePublic,
 			apiContributions:   []string{"foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_stubs_current.from-text",
+			fullApiSurfaceStub: "android_stubs_current",
 		},
 		{
 			scope:              apiScopeSystem,
 			apiContributions:   []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_system_stubs_current.from-text",
+			fullApiSurfaceStub: "android_system_stubs_current",
 		},
 		{
 			scope:              apiScopeTest,
 			apiContributions:   []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
-			fullApiSurfaceStub: "android_test_stubs_current.from-text",
+			fullApiSurfaceStub: "android_test_stubs_current",
 		},
 		{
 			scope:              apiScopeModuleLib,
@@ -1474,3 +1474,32 @@
 		android.AssertStringEquals(t, "Module expected to contain full api surface api library", c.fullApiSurfaceStub, *m.properties.Full_api_surface_stub)
 	}
 }
+
+func TestStaticDepStubLibrariesVisibility(t *testing.T) {
+	android.GroupFixturePreparers(
+		prepareForJavaTest,
+		PrepareForTestWithJavaSdkLibraryFiles,
+		FixtureWithLastReleaseApis("foo"),
+		android.FixtureMergeMockFs(
+			map[string][]byte{
+				"A.java": nil,
+				"dir/Android.bp": []byte(
+					`
+					java_library {
+						name: "bar",
+						srcs: ["A.java"],
+						libs: ["foo.stubs.from-source"],
+					}
+					`),
+				"dir/A.java": nil,
+			},
+		).ExtendWithErrorHandler(
+			android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+				`module "bar" variant "android_common": depends on //.:foo.stubs.from-source which is not visible to this module`)),
+	).RunTestWithBp(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["A.java"],
+		}
+	`)
+}
diff --git a/java/testing.go b/java/testing.go
index 3a238d7..f2bcccf 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -225,6 +225,29 @@
 	)
 }
 
+func FixtureWithPrebuiltIncrementalApis(apiLevel2Modules map[string][]string) android.FixturePreparer {
+	mockFS := android.MockFS{}
+	path := "prebuilts/sdk/Android.bp"
+
+	bp := fmt.Sprintf(`
+			prebuilt_apis {
+				name: "sdk",
+				api_dirs: ["%s"],
+				allow_incremental_platform_api: true,
+				imports_sdk_version: "none",
+				imports_compile_dex: true,
+			}
+		`, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
+
+	for release, modules := range apiLevel2Modules {
+		mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
+	}
+	return android.GroupFixturePreparers(
+		android.FixtureAddTextFile(path, bp),
+		android.FixtureMergeMockFs(mockFS),
+	)
+}
+
 func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte {
 	libs := append([]string{"android"}, modules...)
 
@@ -385,6 +408,8 @@
 		"kotlin-stdlib-jdk8",
 		"kotlin-annotations",
 		"stub-annotations",
+
+		"aconfig-annotations-lib",
 	}
 
 	for _, extra := range extraModules {
diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go
index 5d27c0c..97345af 100644
--- a/provenance/provenance_singleton.go
+++ b/provenance/provenance_singleton.go
@@ -38,7 +38,9 @@
 			Command: `rm -rf $out && ` +
 				`echo "# proto-file: build/soong/provenance/proto/provenance_metadata.proto" > $out && ` +
 				`echo "# proto-message: ProvenanceMetaDataList" >> $out && ` +
-				`for file in $in; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
+				`cat $out.rsp | tr ' ' '\n' | while read -r file || [ -n "$$file" ]; do echo '' >> $out; echo 'metadata {' | cat - $$file | grep -Ev "^#.*|^$$" >> $out; echo '}' >> $out; done`,
+			Rspfile:        `$out.rsp`,
+			RspfileContent: `$in`,
 		})
 )
 
diff --git a/python/bp2build.go b/python/bp2build.go
index cd3f2a1..8bc3d0a 100644
--- a/python/bp2build.go
+++ b/python/bp2build.go
@@ -33,6 +33,12 @@
 
 type bazelPythonProtoLibraryAttributes struct {
 	Deps bazel.LabelListAttribute
+
+	// A list of proto_library targets that the proto_library in `deps` depends on
+	// This list is overestimation.
+	// Overestimation is necessary since Soong includes other protos via proto.include_dirs and not
+	// a specific .proto file module explicitly.
+	Transitive_deps bazel.LabelListAttribute
 }
 
 type baseAttributes struct {
@@ -73,7 +79,6 @@
 
 	if !partitionedSrcs["proto"].IsEmpty() {
 		protoInfo, _ := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, partitionedSrcs["proto"])
-		protoLabel := bazel.Label{Label: ":" + protoInfo.Name}
 
 		pyProtoLibraryName := m.Name() + "_py_proto"
 		ctx.CreateBazelTargetModule(bazel.BazelTargetModuleProperties{
@@ -82,7 +87,8 @@
 		}, android.CommonAttributes{
 			Name: pyProtoLibraryName,
 		}, &bazelPythonProtoLibraryAttributes{
-			Deps: bazel.MakeSingleLabelListAttribute(protoLabel),
+			Deps:            bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
+			Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
 		})
 
 		attrs.Deps.Add(bazel.MakeLabelAttribute(":" + pyProtoLibraryName))
@@ -223,7 +229,8 @@
 
 	props := bazel.BazelTargetModuleProperties{
 		// Use the native py_binary rule.
-		Rule_class: "py_test",
+		Rule_class:        "py_test",
+		Bzl_load_location: "//build/bazel/rules/python:py_test.bzl",
 	}
 
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
diff --git a/python/builder.go b/python/builder.go
index 1066493..2553a77 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -73,14 +73,14 @@
 
 	precompile = pctx.AndroidStaticRule("precompilePython", blueprint.RuleParams{
 		Command: `LD_LIBRARY_PATH="$ldLibraryPath" ` +
-			`PYTHONPATH=$stdlibZip/internal/stdlib ` +
+			`PYTHONPATH=$stdlibZip/internal/$stdlibPkg ` +
 			`$launcher build/soong/python/scripts/precompile_python.py $in $out`,
 		CommandDeps: []string{
 			"$stdlibZip",
 			"$launcher",
 			"build/soong/python/scripts/precompile_python.py",
 		},
-	}, "stdlibZip", "launcher", "ldLibraryPath")
+	}, "stdlibZip", "stdlibPkg", "launcher", "ldLibraryPath")
 )
 
 func init() {
diff --git a/python/proto.go b/python/proto.go
index 400e72c..ad2b786 100644
--- a/python/proto.go
+++ b/python/proto.go
@@ -19,7 +19,8 @@
 )
 
 func genProto(ctx android.ModuleContext, protoFile android.Path, flags android.ProtoFlags) android.Path {
-	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Base()+".srcszip")
+	// Using protoFile.Base() would generate duplicate source errors in some cases, so we use Rel() instead
+	srcsZipFile := android.PathForModuleGen(ctx, protoFile.Rel()+".srcszip")
 
 	outDir := srcsZipFile.ReplaceExtension(ctx, "tmp")
 	depFile := srcsZipFile.ReplaceExtension(ctx, "srcszip.d")
diff --git a/python/python.go b/python/python.go
index 8fde638..7d77ca7 100644
--- a/python/python.go
+++ b/python/python.go
@@ -169,6 +169,7 @@
 	getDataPathMappings() []pathMapping
 	getSrcsZip() android.Path
 	getPrecompiledSrcsZip() android.Path
+	getPkgPath() string
 }
 
 // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination
@@ -191,6 +192,19 @@
 	return p.precompiledSrcsZip
 }
 
+// getPkgPath returns the pkg_path value
+func (p *PythonLibraryModule) getPkgPath() string {
+	return String(p.properties.Pkg_path)
+}
+
+// PkgPath is the "public" version of `getPkgPath` that is only available during bp2build
+func (p *PythonLibraryModule) PkgPath(ctx android.BazelConversionContext) *string {
+	if ctx.Config().BuildMode != android.Bp2build {
+		ctx.ModuleErrorf("PkgPath is only supported in bp2build mode")
+	}
+	return p.properties.Pkg_path
+}
+
 func (p *PythonLibraryModule) getBaseProperties() *BaseProperties {
 	return &p.properties
 }
@@ -370,7 +384,20 @@
 
 		launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++")
 	case pyVersion3:
-		stdLib = "py3-stdlib"
+		var prebuiltStdLib bool
+		if targetForDeps.Os.Bionic() {
+			prebuiltStdLib = false
+		} else if ctx.Config().VendorConfig("cpython3").Bool("force_build_host") {
+			prebuiltStdLib = false
+		} else {
+			prebuiltStdLib = true
+		}
+
+		if prebuiltStdLib {
+			stdLib = "py3-stdlib-prebuilt"
+		} else {
+			stdLib = "py3-stdlib"
+		}
 
 		launcherModule = "py3-launcher"
 		if autorun {
@@ -461,14 +488,19 @@
 	destToPySrcs := make(map[string]string)
 	destToPyData := make(map[string]string)
 
+	// Disable path checks for the stdlib, as it includes a "." in the version string
+	isInternal := proptools.BoolDefault(p.properties.Is_internal, false)
+
 	for _, s := range expandedSrcs {
 		if s.Ext() != pyExt && s.Ext() != protoExt {
 			ctx.PropertyErrorf("srcs", "found non (.py|.proto) file: %q!", s.String())
 			continue
 		}
 		runfilesPath := filepath.Join(pkgPath, s.Rel())
-		if err := isValidPythonPath(runfilesPath); err != nil {
-			ctx.PropertyErrorf("srcs", err.Error())
+		if !isInternal {
+			if err := isValidPythonPath(runfilesPath); err != nil {
+				ctx.PropertyErrorf("srcs", err.Error())
+			}
 		}
 		if !checkForDuplicateOutputPath(ctx, destToPySrcs, runfilesPath, s.String(), p.Name(), p.Name()) {
 			p.srcsPathMappings = append(p.srcsPathMappings, pathMapping{dest: runfilesPath, src: s})
@@ -591,13 +623,16 @@
 	// "cross compiling" for device here purely by virtue of host and device python bytecode
 	// being the same.
 	var stdLib android.Path
+	var stdLibPkg string
 	var launcher android.Path
-	if ctx.ModuleName() == "py3-stdlib" || ctx.ModuleName() == "py2-stdlib" {
+	if proptools.BoolDefault(p.properties.Is_internal, false) {
 		stdLib = p.srcsZip
+		stdLibPkg = p.getPkgPath()
 	} else {
 		ctx.VisitDirectDepsWithTag(hostStdLibTag, func(module android.Module) {
 			if dep, ok := module.(pythonDependency); ok {
 				stdLib = dep.getPrecompiledSrcsZip()
+				stdLibPkg = dep.getPkgPath()
 			}
 		})
 	}
@@ -636,6 +671,7 @@
 		Description: "Precompile the python sources of " + ctx.ModuleName(),
 		Args: map[string]string{
 			"stdlibZip":     stdLib.String(),
+			"stdlibPkg":     stdLibPkg,
 			"launcher":      launcher.String(),
 			"ldLibraryPath": strings.Join(ldLibraryPath, ":"),
 		},
diff --git a/python/tests/par_test.py b/python/tests/par_test.py
index 1e03f16..96b42ae 100644
--- a/python/tests/par_test.py
+++ b/python/tests/par_test.py
@@ -33,6 +33,8 @@
 assert_equal("os.path.basename(__file__)", fileName, "par_test.py")
 
 archive = os.path.dirname(__file__)
+major = sys.version_info.major
+minor = sys.version_info.minor
 
 assert_equal("__package__", __package__, "")
 assert_equal("sys.argv[0]", sys.argv[0], archive)
@@ -42,10 +44,11 @@
 assert_equal("__loader__.archive", __loader__.archive, archive)
 assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
 
-assert_equal("len(sys.path)", len(sys.path), 3)
+assert_equal("len(sys.path)", len(sys.path), 4)
 assert_equal("sys.path[0]", sys.path[0], archive)
-assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal"))
-assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", "stdlib"))
+assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal", f"python{major}{minor}.zip"))
+assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", f"python{major}.{minor}"))
+assert_equal("sys.path[3]", sys.path[3], os.path.join(archive, "internal", f"python{major}.{minor}", "lib-dynload"))
 
 if os.getenv('ARGTEST', False):
     assert_equal("len(sys.argv)", len(sys.argv), 3)
diff --git a/python/tests/py-cmd_test.py b/python/tests/py-cmd_test.py
index c7ba0ab..8aed782 100644
--- a/python/tests/py-cmd_test.py
+++ b/python/tests/py-cmd_test.py
@@ -55,22 +55,22 @@
 assert_equal("sys.prefix", sys.prefix, sys.executable)
 assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
 
-if sys.version_info[0] == 2:
+major = sys.version_info.major
+minor = sys.version_info.minor
+
+if major == 2:
     assert_equal("len(sys.path)", len(sys.path), 4)
     assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
     assert_equal("sys.path[1]", sys.path[1], "/extra")
     assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, "internal"))
     assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, "internal", "stdlib"))
 else:
-    assert_equal("len(sys.path)", len(sys.path), 8)
+    assert_equal("len(sys.path)", len(sys.path), 5)
     assert_equal("sys.path[0]", sys.path[0], os.path.abspath(os.path.dirname(__file__)))
     assert_equal("sys.path[1]", sys.path[1], "/extra")
-    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
-    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), '..'))
-    assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
-    assert_equal("sys.path[5]", sys.path[5], os.path.join(sys.executable, 'lib', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
-    assert_equal("sys.path[6]", sys.path[6], os.path.join(sys.executable, "internal"))
-    assert_equal("sys.path[7]", sys.path[7], os.path.join(sys.executable, "internal", "stdlib"))
+    assert_equal("sys.path[2]", sys.path[2], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + str(sys.version_info[1]) + '.zip'))
+    assert_equal("sys.path[3]", sys.path[3], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])))
+    assert_equal("sys.path[4]", sys.path[4], os.path.join(sys.executable, 'internal', 'python' + str(sys.version_info[0]) + '.' + str(sys.version_info[1]), 'lib-dynload'))
 
 if failed:
     sys.exit(1)
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index f4abae5..c44ec58 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -24,11 +24,16 @@
 fi
 
 if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) ||
-      ( ! -f $ANDROID_HOST_OUT/bin/py2-cmd ) ||
       ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then
   echo "Run 'm par_test py2-cmd py3-cmd' first"
   exit 1
 fi
+if [ $(uname -s) = Linux ]; then
+  if [[ ! -f $ANDROID_HOST_OUT/bin/py2-cmd ]]; then
+    echo "Run 'm par_test py2-cmd py3-cmd' first"
+    exit 1
+  fi
+fi
 
 export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64
 
@@ -42,11 +47,15 @@
 
 cd $(dirname ${BASH_SOURCE[0]})
 
-PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+if [ $(uname -s) = Linux ]; then
+  PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py
+fi
 PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py
 
-ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
-ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+if [ $(uname -s) = Linux ]; then
+  ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2
+  ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2
+fi
 
 ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2
 ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 5e680b0..c684e81 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -61,7 +61,7 @@
 				entries.AddStrings("LOCAL_RLIB_LIBRARIES", mod.Properties.AndroidMkRlibs...)
 				entries.AddStrings("LOCAL_DYLIB_LIBRARIES", mod.Properties.AndroidMkDylibs...)
 				entries.AddStrings("LOCAL_PROC_MACRO_LIBRARIES", mod.Properties.AndroidMkProcMacroLibs...)
-				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.Properties.AndroidMkSharedLibs...)
+				entries.AddStrings("LOCAL_SHARED_LIBRARIES", mod.transitiveAndroidMkSharedLibs.ToList()...)
 				entries.AddStrings("LOCAL_STATIC_LIBRARIES", mod.Properties.AndroidMkStaticLibs...)
 				entries.AddStrings("LOCAL_SOONG_LINK_TYPE", mod.makeLinkType)
 				if mod.UseVndk() {
diff --git a/rust/binary.go b/rust/binary.go
index e6f1539..1e24beb 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -16,6 +16,8 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel"
+	"fmt"
 )
 
 func init() {
@@ -60,6 +62,8 @@
 func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 
+	android.InitBazelModule(module)
+
 	binary := &binaryDecorator{
 		baseCompiler: NewBaseCompiler("bin", "", InstallInSystem),
 	}
@@ -183,3 +187,88 @@
 func (binary *binaryDecorator) testBinary() bool {
 	return false
 }
+
+type rustBinaryLibraryAttributes struct {
+	Srcs            bazel.LabelListAttribute
+	Compile_data    bazel.LabelListAttribute
+	Crate_name      bazel.StringAttribute
+	Edition         bazel.StringAttribute
+	Crate_features  bazel.StringListAttribute
+	Deps            bazel.LabelListAttribute
+	Proc_macro_deps bazel.LabelListAttribute
+	Rustc_flags     bazel.StringListAttribute
+}
+
+func binaryBp2build(ctx android.TopDownMutatorContext, m *Module) {
+	binary := m.compiler.(*binaryDecorator)
+
+	var srcs bazel.LabelList
+	var compileData bazel.LabelList
+
+	if binary.baseCompiler.Properties.Srcs[0] == "src/main.rs" {
+		srcs = android.BazelLabelForModuleSrc(ctx, []string{"src/**/*.rs"})
+		compileData = android.BazelLabelForModuleSrc(
+			ctx,
+			[]string{
+				"src/**/*.proto",
+				"examples/**/*.rs",
+				"**/*.md",
+				"templates/**/*.template",
+			},
+		)
+	} else {
+		srcs = android.BazelLabelForModuleSrc(ctx, binary.baseCompiler.Properties.Srcs)
+	}
+
+	deps := android.BazelLabelForModuleDeps(ctx, append(
+		binary.baseCompiler.Properties.Rustlibs,
+	))
+
+	procMacroDeps := android.BazelLabelForModuleDeps(ctx, binary.baseCompiler.Properties.Proc_macros)
+
+	var rustcFLags []string
+	for _, cfg := range binary.baseCompiler.Properties.Cfgs {
+		rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg))
+	}
+
+	attrs := &rustBinaryLibraryAttributes{
+		Srcs: bazel.MakeLabelListAttribute(
+			srcs,
+		),
+		Compile_data: bazel.MakeLabelListAttribute(
+			compileData,
+		),
+		Crate_name: bazel.StringAttribute{
+			Value: &binary.baseCompiler.Properties.Crate_name,
+		},
+		Edition: bazel.StringAttribute{
+			Value: binary.baseCompiler.Properties.Edition,
+		},
+		Crate_features: bazel.StringListAttribute{
+			Value: binary.baseCompiler.Properties.Features,
+		},
+		Deps: bazel.MakeLabelListAttribute(
+			deps,
+		),
+		Proc_macro_deps: bazel.MakeLabelListAttribute(
+			procMacroDeps,
+		),
+		Rustc_flags: bazel.StringListAttribute{
+			Value: append(
+				rustcFLags,
+				binary.baseCompiler.Properties.Flags...,
+			),
+		},
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "rust_binary",
+			Bzl_load_location: "@rules_rust//rust:defs.bzl",
+		},
+		android.CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs,
+	)
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
index dd4f993..dff94ac 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -21,6 +21,27 @@
 	"android/soong/android"
 )
 
+// Test that rustlibs default linkage is always rlib for host binaries.
+func TestBinaryHostLinkage(t *testing.T) {
+	ctx := testRust(t, `
+		rust_binary_host {
+			name: "fizz-buzz",
+			srcs: ["foo.rs"],
+			rustlibs: ["libfoo"],
+		}
+		rust_library {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+			host_supported: true,
+		}
+	`)
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+	if !android.InList("libfoo.rlib-std", fizzBuzz.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for host binaries")
+	}
+}
+
 // Test that rustlibs default linkage is correct for binaries.
 func TestBinaryLinkage(t *testing.T) {
 	ctx := testRust(t, `
@@ -54,6 +75,12 @@
 	if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
 		t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
 	}
+
+	rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module)
+
+	if !android.InList("libfoo.rlib-std", rlibLinkDevice.Properties.AndroidMkRlibs) {
+		t.Errorf("rustlibs dependency libfoo should be an rlib dep for device modules when prefer_rlib is set")
+	}
 }
 
 // Test that prefer_rlib links in libstd statically as well as rustlibs.
@@ -158,7 +185,7 @@
 	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
 		t.Errorf("static binary not linking against libc as a static library")
 	}
-	if len(fizzMod.Properties.AndroidMkSharedLibs) > 0 {
+	if len(fizzMod.transitiveAndroidMkSharedLibs.ToList()) > 0 {
 		t.Errorf("static binary incorrectly linking against shared libraries")
 	}
 }
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 59585aa..a80a587 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -29,7 +29,7 @@
 	defaultBindgenFlags = []string{""}
 
 	// bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
-	bindgenClangVersion = "clang-r498229"
+	bindgenClangVersion = "clang-r498229b"
 
 	_ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" {
@@ -61,15 +61,18 @@
 		"${cc_config.ClangBase}/${bindgenHostPrebuiltTag}/${bindgenClangVersion}/${bindgenClangLibdir}")
 
 	//TODO(ivanlozano) Switch this to RuleBuilder
+	//
+	//TODO Pass the flag files directly to bindgen e.g. with @file when it supports that.
+	//See https://github.com/rust-lang/rust-bindgen/issues/2508.
 	bindgen = pctx.AndroidStaticRule("bindgen",
 		blueprint.RuleParams{
 			Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
-				"$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+				"$cmd $flags $$(cat $flagfiles) $in -o $out -- -MD -MF $out.d $cflags",
 			CommandDeps: []string{"$cmd"},
 			Deps:        blueprint.DepsGCC,
 			Depfile:     "$out.d",
 		},
-		"cmd", "flags", "cflags")
+		"cmd", "flags", "flagfiles", "cflags")
 )
 
 func init() {
@@ -90,6 +93,9 @@
 	// list of bindgen-specific flags and options
 	Bindgen_flags []string `android:"arch_variant"`
 
+	// list of files containing extra bindgen flags
+	Bindgen_flag_files []string `android:"arch_variant"`
+
 	// module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
 	// binary must expect arguments in a similar fashion to bindgen, e.g.
 	//
@@ -216,6 +222,14 @@
 	bindgenFlags := defaultBindgenFlags
 	bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
 
+	// cat reads from stdin if its command line is empty,
+	// so we pass in /dev/null if there are no other flag files
+	bindgenFlagFiles := []string{"/dev/null"}
+	for _, flagFile := range b.Properties.Bindgen_flag_files {
+		bindgenFlagFiles = append(bindgenFlagFiles, android.PathForModuleSrc(ctx, flagFile).String())
+		implicits = append(implicits, android.PathForModuleSrc(ctx, flagFile))
+	}
+
 	wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
 	if !wrapperFile.Valid() {
 		ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
@@ -261,9 +275,10 @@
 		Input:       wrapperFile.Path(),
 		Implicits:   implicits,
 		Args: map[string]string{
-			"cmd":    cmd,
-			"flags":  strings.Join(bindgenFlags, " "),
-			"cflags": strings.Join(cflags, " "),
+			"cmd":       cmd,
+			"flags":     strings.Join(bindgenFlags, " "),
+			"flagfiles": strings.Join(bindgenFlagFiles, " "),
+			"cflags":    strings.Join(cflags, " "),
 		},
 	})
 
@@ -279,7 +294,7 @@
 // rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input.
 // Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure
 // the header and generated source is appropriately handled. It is recommended to add it as a dependency in the
-// rlibs, dylibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
+// rlibs or rustlibs property. It may also be added in the srcs property for external crates, using the ":"
 // prefix.
 func RustBindgenFactory() android.Module {
 	module, _ := NewRustBindgen(android.HostAndDeviceSupported)
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index af04cfc..12cdb3c 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -168,3 +168,28 @@
 		}
 	`)
 }
+
+func TestBindgenFlagFile(t *testing.T) {
+	ctx := testRust(t, `
+		rust_bindgen {
+			name: "libbindgen",
+			wrapper_src: "src/any.h",
+			crate_name: "bindgen",
+			stem: "libbindgen",
+			source_stem: "bindings",
+			bindgen_flag_files: [
+				"flag_file.txt",
+			],
+		}
+	`)
+	libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs")
+
+	if !strings.Contains(libbindgen.Args["flagfiles"], "/dev/null") {
+		t.Errorf("missing /dev/null in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+	}
+	if !strings.Contains(libbindgen.Args["flagfiles"], "flag_file.txt") {
+		t.Errorf("missing bindgen flags file in rust_bindgen rule: flags %#v", libbindgen.Args["flagfiles"])
+	}
+	// TODO: The best we can do right now is check $flagfiles. Once bindgen.go switches to RuleBuilder,
+	// we may be able to check libbinder.RuleParams.Command to see if it contains $(cat /dev/null flag_file.txt)
+}
diff --git a/rust/builder.go b/rust/builder.go
index c31bc88..b1f049d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -45,9 +45,9 @@
 		"rustcFlags", "libFlags", "envVars")
 	rustLink = pctx.AndroidStaticRule("rustLink",
 		blueprint.RuleParams{
-			Command: "${config.RustLinker} -o $out ${crtBegin} ${config.RustLinkerArgs} @$in ${linkFlags} ${crtEnd}",
+			Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}",
 		},
-		"linkFlags", "crtBegin", "crtEnd")
+		"earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd")
 
 	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
 	rustdoc = pctx.AndroidStaticRule("rustdoc",
@@ -228,11 +228,26 @@
 		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
 		if pkgVersion != "" {
 			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+
+			// Ensure the version is in the form of "x.y.z" (approximately semver compliant).
+			//
+			// For our purposes, we don't care to enforce that these are integers since they may
+			// include other characters at times (e.g. sometimes the patch version is more than an integer).
+			if strings.Count(pkgVersion, ".") == 2 {
+				var semver_parts = strings.Split(pkgVersion, ".")
+				envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0])
+				envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1])
+				envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2])
+			}
 		}
 	}
 
 	envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
 
+	if ctx.Darwin() {
+		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
+	}
+
 	return envVars
 }
 
@@ -243,6 +258,7 @@
 	var implicits, linkImplicits, linkOrderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
+	var earlyLinkFlags string
 
 	output.outputFile = outputFile
 	crateName := ctx.RustModule().CrateName()
@@ -281,6 +297,10 @@
 	}
 
 	// Collect linker flags
+	if !ctx.Darwin() {
+		earlyLinkFlags = "-Wl,--as-needed"
+	}
+
 	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
 	linkFlags = append(linkFlags, flags.LinkFlags...)
 
@@ -380,9 +400,10 @@
 			Implicits:   linkImplicits,
 			OrderOnly:   linkOrderOnly,
 			Args: map[string]string{
-				"linkFlags": strings.Join(linkFlags, " "),
-				"crtBegin":  strings.Join(deps.CrtBegin.Strings(), " "),
-				"crtEnd":    strings.Join(deps.CrtEnd.Strings(), " "),
+				"earlyLinkFlags": earlyLinkFlags,
+				"linkFlags":      strings.Join(linkFlags, " "),
+				"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
+				"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
 			},
 		})
 	}
diff --git a/rust/compiler.go b/rust/compiler.go
index 06ae12f..e6a7a93 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -91,10 +91,8 @@
 	// list of rust rlib crate dependencies
 	Rlibs []string `android:"arch_variant"`
 
-	// list of rust dylib crate dependencies
-	Dylibs []string `android:"arch_variant"`
-
-	// list of rust automatic crate dependencies
+	// list of rust automatic crate dependencies.
+	// Rustlibs linkage is rlib for host targets and dylib for device targets.
 	Rustlibs []string `android:"arch_variant"`
 
 	// list of rust proc_macro crate dependencies
@@ -320,6 +318,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.
+		flags.LinkFlags = append(flags.LinkFlags,
+			"-ldl",
+			"-lpthread",
+			"-lm",
+		)
+	}
 	return flags
 }
 
@@ -359,7 +366,6 @@
 
 func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
 	deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
-	deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
 	deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
 	deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
 	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index ae783e8..08ac2ef 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -26,11 +26,18 @@
 	Arm64LinkFlags            = []string{}
 
 	Arm64ArchVariantRustFlags = map[string][]string{
-		"armv8-a":            []string{},
-		"armv8-a-branchprot": []string{},
-		"armv8-2a":           []string{},
-		"armv8-2a-dotprod":   []string{},
-		"armv9-a":            []string{},
+		"armv8-a": []string{},
+		"armv8-a-branchprot": []string{
+			// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+			"-Z branch-protection=bti,pac-ret",
+		},
+		"armv8-2a":         []string{},
+		"armv8-2a-dotprod": []string{},
+		"armv9-a": []string{
+			// branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard
+			"-Z branch-protection=bti,pac-ret",
+			"-Z stack-protector=none",
+		},
 	}
 )
 
diff --git a/rust/config/global.go b/rust/config/global.go
index c39341e..4bd495d 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -21,9 +21,10 @@
 	_ "android/soong/cc/config"
 )
 
-var pctx = android.NewPackageContext("android/soong/rust/config")
-
 var (
+	pctx         = android.NewPackageContext("android/soong/rust/config")
+	exportedVars = android.NewExportedVariables(pctx)
+
 	RustDefaultVersion = "1.71.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
@@ -53,11 +54,11 @@
 		"-C symbol-mangling-version=v0",
 		"--color always",
 		"-Zdylib-lto",
+		"-Z link-native-libraries=no",
 	}
 
 	deviceGlobalRustFlags = []string{
 		"-C panic=abort",
-		"-Z link-native-libraries=no",
 		// Generate additional debug info for AutoFDO
 		"-Z debug-info-for-profiling",
 	}
@@ -102,10 +103,10 @@
 
 	pctx.ImportAs("cc_config", "android/soong/cc/config")
 	pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
-	pctx.StaticVariable("RustLinkerArgs", "-Wl,--as-needed")
 
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
+	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
 }
 
 func getRustVersionPctx(ctx android.PackageVarContext) string {
@@ -118,3 +119,8 @@
 	}
 	return RustDefaultVersion
 }
+
+// BazelRustToolchainVars returns a string with
+func BazelRustToolchainVars(config android.Config) string {
+	return android.BazelToolchainVars(config, exportedVars)
+}
diff --git a/rust/config/lints.go b/rust/config/lints.go
index ef6b315..9322981 100644
--- a/rust/config/lints.go
+++ b/rust/config/lints.go
@@ -46,6 +46,7 @@
 		"-A deprecated",
 		"-D missing-docs",
 		"-D warnings",
+		"-D unsafe_op_in_unsafe_fn",
 	}
 	// Default Clippy lints. These are applied on top of defaultRustcLints.
 	// It should be assumed that any warning lint will be promoted to a
@@ -55,6 +56,7 @@
 		"-A clippy::unnecessary-wraps",
 		"-A clippy::unusual-byte-groupings",
 		"-A clippy::upper-case-acronyms",
+		"-D clippy::undocumented_unsafe_blocks",
 	}
 
 	// Rust lints for vendor code.
diff --git a/rust/fuzz.go b/rust/fuzz.go
index c2b9405..4c04ce8 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -25,6 +25,7 @@
 
 func init() {
 	android.RegisterModuleType("rust_fuzz", RustFuzzFactory)
+	android.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
 }
 
 type fuzzDecorator struct {
@@ -43,6 +44,11 @@
 	return module.Init()
 }
 
+func RustFuzzHostFactory() android.Module {
+	module, _ := NewRustFuzz(android.HostSupported)
+	return module.Init()
+}
+
 func NewRustFuzz(hod android.HostOrDeviceSupported) (*Module, *fuzzDecorator) {
 	module, binary := NewRustBinary(hod)
 	fuzz := &fuzzDecorator{
@@ -54,6 +60,25 @@
 	fuzz.binaryDecorator.baseCompiler.dir64 = "fuzz"
 	fuzz.binaryDecorator.baseCompiler.location = InstallInData
 	module.sanitize.SetSanitizer(cc.Fuzzer, true)
+
+	// The fuzzer runtime is not present for darwin or bionic host modules, so disable rust_fuzz modules for these.
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+
+		extraProps := struct {
+			Target struct {
+				Darwin struct {
+					Enabled *bool
+				}
+				Linux_bionic struct {
+					Enabled *bool
+				}
+			}
+		}{}
+		extraProps.Target.Darwin.Enabled = cc.BoolPtr(false)
+		extraProps.Target.Linux_bionic.Enabled = cc.BoolPtr(false)
+		ctx.AppendProperties(&extraProps)
+	})
+
 	module.compiler = fuzz
 	return module, fuzz
 }
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 0aecf61..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -34,6 +34,10 @@
 				srcs: ["foo.rs"],
 				rustlibs: ["libtest_fuzzing"],
 			}
+			rust_fuzz_host {
+				name: "host_fuzzer",
+				srcs: ["foo.rs"],
+			}
 	`)
 
 	// Check that appropriate dependencies are added and that the rustlib linkage is correct.
@@ -50,7 +54,13 @@
 	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
 		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
+	}
 
+	// Check that host modules support fuzzing.
+	host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
+	if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that dependencies have 'fuzzer' variants produced for them as well.
diff --git a/rust/library.go b/rust/library.go
index 3f480a2..3f031c1 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -20,7 +20,10 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -398,6 +401,8 @@
 func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module := newModule(hod, android.MultilibBoth)
 
+	android.InitBazelModule(module)
+
 	library := &libraryDecorator{
 		MutatedProperties: LibraryMutatedProperties{
 			BuildDylib:  false,
@@ -466,7 +471,15 @@
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
 	}
 	if library.shared() {
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+		if ctx.Darwin() {
+			flags.LinkFlags = append(
+				flags.LinkFlags,
+				"-dynamic_lib",
+				"-install_name @rpath/"+library.sharedLibFilename(ctx),
+			)
+		} else {
+			flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+		}
 	}
 
 	return flags
@@ -785,3 +798,155 @@
 	// TODO(185577950): If support for generated headers is added, they need to be collected here as well.
 	l.collectedSnapshotHeaders = ret
 }
+
+type rustLibraryAttributes struct {
+	Srcs            bazel.LabelListAttribute
+	Compile_data    bazel.LabelListAttribute
+	Crate_name      bazel.StringAttribute
+	Edition         bazel.StringAttribute
+	Crate_features  bazel.StringListAttribute
+	Deps            bazel.LabelListAttribute
+	Rustc_flags     bazel.StringListAttribute
+	Proc_macro_deps bazel.LabelListAttribute
+}
+
+func libraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
+	lib := m.compiler.(*libraryDecorator)
+
+	srcs, compileData := srcsAndCompileDataAttrs(ctx, *lib.baseCompiler)
+
+	deps := android.BazelLabelForModuleDeps(ctx, append(
+		lib.baseCompiler.Properties.Rustlibs,
+		lib.baseCompiler.Properties.Rlibs...,
+	))
+
+	cargoBuildScript := cargoBuildScriptBp2build(ctx, m)
+	if cargoBuildScript != nil {
+		deps.Add(&bazel.Label{
+			Label: ":" + *cargoBuildScript,
+		})
+	}
+
+	procMacroDeps := android.BazelLabelForModuleDeps(ctx, lib.baseCompiler.Properties.Proc_macros)
+
+	var rustcFLags []string
+	for _, cfg := range lib.baseCompiler.Properties.Cfgs {
+		rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg))
+	}
+
+	attrs := &rustLibraryAttributes{
+		Srcs: bazel.MakeLabelListAttribute(
+			srcs,
+		),
+		Compile_data: bazel.MakeLabelListAttribute(
+			compileData,
+		),
+		Crate_name: bazel.StringAttribute{
+			Value: &lib.baseCompiler.Properties.Crate_name,
+		},
+		Edition: bazel.StringAttribute{
+			Value: lib.baseCompiler.Properties.Edition,
+		},
+		Crate_features: bazel.StringListAttribute{
+			Value: lib.baseCompiler.Properties.Features,
+		},
+		Deps: bazel.MakeLabelListAttribute(
+			deps,
+		),
+		Proc_macro_deps: bazel.MakeLabelListAttribute(
+			procMacroDeps,
+		),
+		Rustc_flags: bazel.StringListAttribute{
+			Value: append(
+				rustcFLags,
+				lib.baseCompiler.Properties.Flags...,
+			),
+		},
+	}
+
+	// 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(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "rust_library",
+			Bzl_load_location: "@rules_rust//rust:defs.bzl",
+		},
+		android.CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs,
+		restriction,
+	)
+}
+
+type cargoBuildScriptAttributes struct {
+	Srcs    bazel.LabelListAttribute
+	Edition bazel.StringAttribute
+	Version bazel.StringAttribute
+}
+
+func cargoBuildScriptBp2build(ctx android.TopDownMutatorContext, m *Module) *string {
+	// Soong treats some crates like libprotobuf as special in that they have
+	// cargo build script ran to produce an out folder and check it into AOSP
+	// For example, https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/out/
+	// is produced by cargo build script https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/build.rs
+	// The out folder is then fed into `rust_library` by a genrule
+	// https://cs.android.com/android/platform/superproject/main/+/main:external/rust/crates/protobuf/Android.bp;l=22
+	// This allows Soong to decouple from cargo completely.
+
+	// Soong decouples from cargo so that it has control over cc compilation.
+	// https://cs.android.com/android/platform/superproject/main/+/main:development/scripts/cargo2android.py;l=1033-1041;drc=8449944a50a0445a5ecaf9b7aed12608c81bf3f1
+	// generates a `cc_library_static` module to have custom cc flags.
+	// Since bp2build will convert the cc modules to cc targets which include the cflags,
+	// Bazel does not need to have this optimization.
+
+	// Performance-wise: rust_library -> cargo_build_script vs rust_library -> genrule (like Soong)
+	// don't have any major difference in build time in Bazel. So using cargo_build_script does not slow
+	// down the build.
+
+	// The benefit of using `cargo_build_script` here is that it would take care of setting correct
+	// `OUT_DIR` for us - similar to what Soong does here
+	// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/rust/builder.go;l=202-218;drc=f29ca58e88c5846bbe8955e5192135e5ab4f14a1
+
+	// TODO(b/297364081): cargo2android.py has logic for when generate/not cc_library_static and out directory
+	// bp2build might be able use the same logic for when to use `cargo_build_script`.
+	// For now, we're building libprotobuf_build_script as a one-off until we have a more principled solution
+	if m.Name() != "libprotobuf" {
+		return nil
+	}
+
+	lib := m.compiler.(*libraryDecorator)
+
+	name := m.Name() + "_build_script"
+	attrs := &cargoBuildScriptAttributes{
+		Srcs: bazel.MakeLabelListAttribute(
+			android.BazelLabelForModuleSrc(ctx, []string{"build.rs"}),
+		),
+		Edition: bazel.StringAttribute{
+			Value: lib.baseCompiler.Properties.Edition,
+		},
+		Version: bazel.StringAttribute{
+			Value: lib.baseCompiler.Properties.Cargo_pkg_version,
+		},
+	}
+
+	// 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(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "cargo_build_script",
+			Bzl_load_location: "@rules_rust//cargo:cargo_build_script.bzl",
+		},
+		android.CommonAttributes{
+			Name: name,
+		},
+		attrs,
+		restriction,
+	)
+
+	return &name
+}
diff --git a/rust/library_test.go b/rust/library_test.go
index add7173..30ef333 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -196,6 +196,65 @@
 	}
 }
 
+func TestNativeDependencyOfRlib(t *testing.T) {
+	ctx := testRust(t, `
+		rust_ffi_static {
+			name: "libffi_static",
+			crate_name: "ffi_static",
+			rlibs: ["librust_rlib"],
+			srcs: ["foo.rs"],
+		}
+		rust_library_rlib {
+			name: "librust_rlib",
+			crate_name: "rust_rlib",
+			srcs: ["foo.rs"],
+			shared_libs: ["shared_cc_dep"],
+			static_libs: ["static_cc_dep"],
+		}
+		cc_library_shared {
+			name: "shared_cc_dep",
+			srcs: ["foo.cpp"],
+		}
+		cc_library_static {
+			name: "static_cc_dep",
+			srcs: ["foo.cpp"],
+		}
+		`)
+
+	rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
+	rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
+	ffiStatic := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_static")
+
+	modules := []android.TestingModule{
+		rustRlibRlibStd,
+		rustRlibDylibStd,
+		ffiStatic,
+	}
+
+	// librust_rlib specifies -L flag to cc deps output directory on rustc command
+	// and re-export the cc deps to rdep libffi_static
+	// When building rlib crate, rustc doesn't link the native libraries
+	// The build system assumes the  cc deps will be at the final linkage (either a shared library or binary)
+	// Hence, these flags are no-op
+	// TODO: We could consider removing these flags
+	for _, module := range modules {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") {
+			t.Errorf(
+				"missing -L flag for shared_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
+			)
+		}
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") {
+			t.Errorf(
+				"missing -L flag for static_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
+			)
+		}
+	}
+}
+
 // Test that variants pull in the right type of rustlib autodep
 func TestAutoDeps(t *testing.T) {
 
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 832b62c..26227d0 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -16,6 +16,8 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel"
+	"fmt"
 )
 
 func init() {
@@ -47,6 +49,8 @@
 func NewProcMacro(hod android.HostOrDeviceSupported) (*Module, *procMacroDecorator) {
 	module := newModule(hod, android.MultilibFirst)
 
+	android.InitBazelModule(module)
+
 	procMacro := &procMacroDecorator{
 		baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
 		flagExporter: NewFlagExporter(),
@@ -99,3 +103,65 @@
 	// Proc_macros are never installed
 	return false
 }
+
+type procMacroAttributes struct {
+	Srcs           bazel.LabelListAttribute
+	Compile_data   bazel.LabelListAttribute
+	Crate_name     bazel.StringAttribute
+	Edition        bazel.StringAttribute
+	Crate_features bazel.StringListAttribute
+	Deps           bazel.LabelListAttribute
+	Rustc_flags    bazel.StringListAttribute
+}
+
+func procMacroBp2build(ctx android.TopDownMutatorContext, m *Module) {
+	procMacro := m.compiler.(*procMacroDecorator)
+	srcs, compileData := srcsAndCompileDataAttrs(ctx, *procMacro.baseCompiler)
+	deps := android.BazelLabelForModuleDeps(ctx, append(
+		procMacro.baseCompiler.Properties.Rustlibs,
+		procMacro.baseCompiler.Properties.Rlibs...,
+	))
+
+	var rustcFLags []string
+	for _, cfg := range procMacro.baseCompiler.Properties.Cfgs {
+		rustcFLags = append(rustcFLags, fmt.Sprintf("--cfg=%s", cfg))
+	}
+
+	attrs := &procMacroAttributes{
+		Srcs: bazel.MakeLabelListAttribute(
+			srcs,
+		),
+		Compile_data: bazel.MakeLabelListAttribute(
+			compileData,
+		),
+		Crate_name: bazel.StringAttribute{
+			Value: &procMacro.baseCompiler.Properties.Crate_name,
+		},
+		Edition: bazel.StringAttribute{
+			Value: procMacro.baseCompiler.Properties.Edition,
+		},
+		Crate_features: bazel.StringListAttribute{
+			Value: procMacro.baseCompiler.Properties.Features,
+		},
+		Deps: bazel.MakeLabelListAttribute(
+			deps,
+		),
+		Rustc_flags: bazel.StringListAttribute{
+			Value: append(
+				rustcFLags,
+				procMacro.baseCompiler.Properties.Flags...,
+			),
+		},
+	}
+	// m.IsConvertedByBp2build()
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "rust_proc_macro",
+			Bzl_load_location: "@rules_rust//rust:defs.bzl",
+		},
+		android.CommonAttributes{
+			Name: m.Name(),
+		},
+		attrs,
+	)
+}
diff --git a/rust/protobuf.go b/rust/protobuf.go
index 0cf6e8c..ae82844 100644
--- a/rust/protobuf.go
+++ b/rust/protobuf.go
@@ -19,6 +19,9 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/bazel"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -243,7 +246,7 @@
 
 // rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for
 // protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will
-// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// create library variants that can be used as a crate dependency by adding it to the rlibs and rustlibs
 // properties of other modules.
 func RustProtobufFactory() android.Module {
 	module, _ := NewRustProtobuf(android.HostAndDeviceSupported)
@@ -264,5 +267,71 @@
 
 	module := NewSourceProviderModule(hod, protobuf, false, false)
 
+	android.InitBazelModule(module)
+
 	return module, protobuf
 }
+
+type rustProtoAttributes struct {
+	Srcs       bazel.LabelListAttribute
+	Crate_name bazel.StringAttribute
+	Deps       bazel.LabelListAttribute
+}
+
+type protoLibraryAttributes struct {
+	Srcs bazel.LabelListAttribute
+}
+
+func protoLibraryBp2build(ctx android.TopDownMutatorContext, m *Module) {
+	var protoFiles []string
+
+	for _, propsInterface := range m.sourceProvider.SourceProviderProps() {
+		if possibleProps, ok := propsInterface.(*ProtobufProperties); ok {
+			protoFiles = possibleProps.Protos
+			break
+		}
+	}
+
+	protoLibraryName := m.Name() + "_proto"
+
+	protoDeps := bazel.LabelListAttribute{
+		Value: bazel.LabelList{
+			Includes: []bazel.Label{
+				{
+					Label:              ":" + protoLibraryName,
+					OriginalModuleName: m.Name(),
+				},
+			},
+		},
+	}
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class: "proto_library",
+		},
+		android.CommonAttributes{
+			Name: protoLibraryName,
+		},
+		&protoLibraryAttributes{
+			Srcs: bazel.MakeLabelListAttribute(
+				android.BazelLabelForModuleSrc(ctx, protoFiles),
+			),
+		},
+	)
+
+	ctx.CreateBazelTargetModule(
+		bazel.BazelTargetModuleProperties{
+			Rule_class:        "rust_proto_library",
+			Bzl_load_location: "@rules_rust//proto/protobuf:defs.bzl",
+		},
+		android.CommonAttributes{
+			Name: m.Name(),
+		},
+		&rustProtoAttributes{
+			Crate_name: bazel.StringAttribute{
+				Value: proptools.StringPtr(m.CrateName()),
+			},
+			Deps: protoDeps,
+		},
+	)
+}
diff --git a/rust/rust.go b/rust/rust.go
index 05fceee..1ee99cd 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -15,7 +15,9 @@
 package rust
 
 import (
+	"android/soong/bazel"
 	"android/soong/bloaty"
+	"android/soong/ui/metrics/bp2build_metrics_proto"
 	"fmt"
 	"strings"
 
@@ -66,7 +68,6 @@
 	AndroidMkRlibs         []string `blueprint:"mutated"`
 	AndroidMkDylibs        []string `blueprint:"mutated"`
 	AndroidMkProcMacroLibs []string `blueprint:"mutated"`
-	AndroidMkSharedLibs    []string `blueprint:"mutated"`
 	AndroidMkStaticLibs    []string `blueprint:"mutated"`
 
 	ImageVariationPrefix string `blueprint:"mutated"`
@@ -168,6 +169,10 @@
 
 	// For apex variants, this is set as apex.min_sdk_version
 	apexSdkVersion android.ApiLevel
+
+	transitiveAndroidMkSharedLibs *android.DepSet[string]
+
+	android.BazelModuleBase
 }
 
 func (mod *Module) Header() bool {
@@ -613,6 +618,7 @@
 		&cc.RustBindgenClangProperties{},
 		&ClippyProperties{},
 		&SanitizeProperties{},
+		&fuzz.FuzzProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -1217,6 +1223,9 @@
 		})
 	}
 
+	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
+	var directAndroidMkSharedLibs []string
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1224,6 +1233,11 @@
 		if _, exists := skipModuleList[depName]; exists {
 			return
 		}
+
+		if depTag == android.DarwinUniversalVariantTag {
+			return
+		}
+
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
 			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1255,6 +1269,8 @@
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
 			}
 
+			transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
+
 			if android.IsSourceDepTagWithOutputTag(depTag, "") {
 				// Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
 				// OS/Arch variant is used.
@@ -1306,12 +1322,17 @@
 				}
 			}
 			linkObject := ccDep.OutputFile()
-			linkPath := linkPathFromFilePath(linkObject.Path())
-
 			if !linkObject.Valid() {
-				ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+				if !ctx.Config().AllowMissingDependencies() {
+					ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+				} else {
+					ctx.AddMissingDependencies([]string{depName})
+				}
+				return
 			}
 
+			linkPath := linkPathFromFilePath(linkObject.Path())
+
 			exportDep := false
 			switch {
 			case cc.IsStaticDepTag(depTag):
@@ -1356,6 +1377,14 @@
 				// Re-get linkObject as ChooseStubOrImpl actually tells us which
 				// object (either from stub or non-stub) to use.
 				linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary)
+				if !linkObject.Valid() {
+					if !ctx.Config().AllowMissingDependencies() {
+						ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
+					} else {
+						ctx.AddMissingDependencies([]string{depName})
+					}
+					return
+				}
 				linkPath = linkPathFromFilePath(linkObject.Path())
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
@@ -1369,7 +1398,7 @@
 				// Record baseLibName for snapshots.
 				mod.Properties.SnapshotSharedLibs = append(mod.Properties.SnapshotSharedLibs, cc.BaseLibName(depName))
 
-				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, makeLibName)
+				directAndroidMkSharedLibs = append(directAndroidMkSharedLibs, makeLibName)
 				exportDep = true
 			case cc.IsHeaderDepTag(depTag):
 				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
@@ -1406,6 +1435,8 @@
 		}
 	})
 
+	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+
 	var rlibDepFiles RustLibraries
 	for _, dep := range directRlibDeps {
 		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
@@ -1814,6 +1845,46 @@
 	return ""
 }
 
+func (m *Module) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	if ctx.ModuleType() == "rust_library_host" || ctx.ModuleType() == "rust_library" {
+		libraryBp2build(ctx, m)
+	} else if ctx.ModuleType() == "rust_proc_macro" {
+		procMacroBp2build(ctx, m)
+	} else if ctx.ModuleType() == "rust_binary_host" {
+		binaryBp2build(ctx, m)
+	} else if ctx.ModuleType() == "rust_protobuf_host" {
+		protoLibraryBp2build(ctx, m)
+	} else {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
+	}
+}
+
+// This is a workaround by assuming the conventions that rust crate repos are structured
+// while waiting for the sandboxing work to complete.
+// TODO(b/297344471): When crate_root prop is set which enforces inputs sandboxing,
+// always use `srcs` and `compile_data` props to generate `srcs` and `compile_data` attributes
+// instead of using globs.
+func srcsAndCompileDataAttrs(ctx android.TopDownMutatorContext, c baseCompiler) (bazel.LabelList, bazel.LabelList) {
+	var srcs bazel.LabelList
+	var compileData bazel.LabelList
+
+	if c.Properties.Srcs[0] == "src/lib.rs" {
+		srcs = android.BazelLabelForModuleSrc(ctx, []string{"src/**/*.rs"})
+		compileData = android.BazelLabelForModuleSrc(
+			ctx,
+			[]string{
+				"src/**/*.proto",
+				"examples/**/*.rs",
+				"**/*.md",
+			},
+		)
+	} else {
+		srcs = android.BazelLabelForModuleSrc(ctx, c.Properties.Srcs)
+	}
+
+	return srcs, compileData
+}
+
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 3f4e296..835114c 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -232,11 +232,6 @@
 			srcs: ["foo.rs"],
 			crate_name: "shared",
 		}
-		rust_library_host_dylib {
-			name: "libdylib",
-			srcs: ["foo.rs"],
-			crate_name: "dylib",
-		}
 		rust_library_host_rlib {
 			name: "librlib",
 			srcs: ["foo.rs"],
@@ -252,7 +247,6 @@
 		}
 		rust_binary_host {
 			name: "fizz-buzz",
-			dylibs: ["libdylib"],
 			rlibs: ["librlib"],
 			proc_macros: ["libpm"],
 			static_libs: ["libstatic"],
@@ -265,10 +259,6 @@
 	rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
-	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
-		t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)")
-	}
-
 	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
 		t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)")
 	}
@@ -277,7 +267,7 @@
 		t.Errorf("Proc_macro dependency not detected (dependency missing from AndroidMkProcMacroLibs)")
 	}
 
-	if !android.InList("libshared", module.Properties.AndroidMkSharedLibs) {
+	if !android.InList("libshared", module.transitiveAndroidMkSharedLibs.ToList()) {
 		t.Errorf("Shared library dependency not detected (dependency missing from AndroidMkSharedLibs)")
 	}
 
diff --git a/rust/sanitize.go b/rust/sanitize.go
index 0f7cf6e..2f5afd7 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -208,9 +208,14 @@
 		s.Memtag_heap = nil
 	}
 
+	// Disable sanitizers for musl x86 modules, rustc does not support any sanitizers.
+	if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 {
+		s.Never = boolPtr(true)
+	}
+
 	// TODO:(b/178369775)
-	// For now sanitizing is only supported on devices
-	if ctx.Os() == android.Android && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
+	// For now sanitizing is only supported on non-windows targets
+	if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
 		sanitize.Properties.SanitizerEnabled = true
 	}
 }
@@ -223,12 +228,22 @@
 	if !sanitize.Properties.SanitizerEnabled {
 		return flags, deps
 	}
+
 	if Bool(sanitize.Properties.Sanitize.Fuzzer) {
 		flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
-	} else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
+	}
+
+	if Bool(sanitize.Properties.Sanitize.Hwaddress) {
 		flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
-	} else if Bool(sanitize.Properties.Sanitize.Address) {
+	}
+
+	if Bool(sanitize.Properties.Sanitize.Address) {
 		flags.RustFlags = append(flags.RustFlags, asanFlags...)
+		if ctx.Host() {
+			// -nodefaultlibs (provided with libc++) prevents the driver from linking
+			// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
+			flags.LinkFlags = append(flags.LinkFlags, []string{"-Wl,--no-as-needed"}...)
+		}
 	}
 	return flags, deps
 }
@@ -267,14 +282,19 @@
 		var depTag blueprint.DependencyTag
 		var deps []string
 
-		if mod.IsSanitizerEnabled(cc.Asan) ||
-			(mod.IsSanitizerEnabled(cc.Fuzzer) && (mctx.Arch().ArchType != android.Arm64 || !mctx.Os().Bionic())) {
-			variations = append(variations,
-				blueprint.Variation{Mutator: "link", Variation: "shared"})
-			depTag = cc.SharedDepTag()
-			deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
-		} else if mod.IsSanitizerEnabled(cc.Hwasan) ||
-			(mod.IsSanitizerEnabled(cc.Fuzzer) && mctx.Arch().ArchType == android.Arm64 && mctx.Os().Bionic()) {
+		if mod.IsSanitizerEnabled(cc.Asan) {
+			if mod.Host() {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "link", Variation: "static"})
+				depTag = cc.StaticDepTag(false)
+				deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan.static")}
+			} else {
+				variations = append(variations,
+					blueprint.Variation{Mutator: "link", Variation: "shared"})
+				depTag = cc.SharedDepTag()
+				deps = []string{config.LibclangRuntimeLibrary(mod.toolchain(mctx), "asan")}
+			}
+		} else if mod.IsSanitizerEnabled(cc.Hwasan) {
 			// TODO(b/204776996): HWASan for static Rust binaries isn't supported yet.
 			if binary, ok := mod.compiler.(binaryInterface); ok {
 				if binary.staticallyLinked() {
@@ -388,7 +408,8 @@
 }
 
 func (mod *Module) SanitizerSupported(t cc.SanitizerType) bool {
-	if mod.Host() {
+	// Sanitizers are not supported on Windows targets.
+	if mod.Os() == android.Windows {
 		return false
 	}
 	switch t {
@@ -414,7 +435,8 @@
 }
 
 func (mod *Module) IsSanitizerExplicitlyDisabled(t cc.SanitizerType) bool {
-	if mod.Host() {
+	// Sanitizers are not supported on Windows targets.
+	if mod.Os() == android.Windows {
 		return true
 	}
 
diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go
index 32d3916..42e3cef 100644
--- a/rust/snapshot_prebuilt.go
+++ b/rust/snapshot_prebuilt.go
@@ -15,6 +15,8 @@
 package rust
 
 import (
+	"fmt"
+
 	"android/soong/android"
 	"android/soong/cc"
 
@@ -26,17 +28,80 @@
 	*libraryDecorator
 	properties          cc.SnapshotLibraryProperties
 	sanitizerProperties struct {
-		CfiEnabled bool `blueprint:"mutated"`
+		SanitizerVariation cc.SanitizerType `blueprint:"mutated"`
 
-		// Library flags for cfi variant.
-		Cfi cc.SnapshotLibraryProperties `android:"arch_variant"`
+		//TODO: Library flags for cfi variant when CFI is supported.
+		//Cfi cc.SnapshotLibraryProperties `android:"arch_variant"`
+
+		// Library flags for hwasan variant.
+		Hwasan cc.SnapshotLibraryProperties `android:"arch_variant"`
 	}
 }
 
+var _ cc.SnapshotSanitizer = (*snapshotLibraryDecorator)(nil)
+
+func (library *snapshotLibraryDecorator) IsSanitizerAvailable(t cc.SanitizerType) bool {
+	switch t {
+	//TODO: When CFI is supported, add a check here as well
+	case cc.Hwasan:
+		return library.sanitizerProperties.Hwasan.Src != nil
+	default:
+		return false
+	}
+}
+
+func (library *snapshotLibraryDecorator) SetSanitizerVariation(t cc.SanitizerType, enabled bool) {
+	if !enabled || library.IsSanitizerEnabled(t) {
+		return
+	}
+	if !library.IsUnsanitizedVariant() {
+		panic(fmt.Errorf("snapshot Sanitizer must be one of Cfi or Hwasan but not both"))
+	}
+	library.sanitizerProperties.SanitizerVariation = t
+}
+
+func (library *snapshotLibraryDecorator) IsSanitizerEnabled(t cc.SanitizerType) bool {
+	return library.sanitizerProperties.SanitizerVariation == t
+}
+
+func (library *snapshotLibraryDecorator) IsUnsanitizedVariant() bool {
+	//TODO: When CFI is supported, add a check here as well
+	return !library.IsSanitizerEnabled(cc.Hwasan)
+}
+
 func init() {
 	registerRustSnapshotModules(android.InitRegistrationContext)
 }
 
+func (mod *Module) IsSnapshotSanitizerAvailable(t cc.SanitizerType) bool {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return ss.IsSanitizerAvailable(t)
+	}
+	return false
+}
+
+func (mod *Module) SetSnapshotSanitizerVariation(t cc.SanitizerType, enabled bool) {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		ss.SetSanitizerVariation(t, enabled)
+	} else {
+		panic(fmt.Errorf("Calling SetSnapshotSanitizerVariation on a non-snapshotLibraryDecorator: %s", mod.Name()))
+	}
+}
+
+func (mod *Module) IsSnapshotUnsanitizedVariant() bool {
+	if ss, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return ss.IsUnsanitizedVariant()
+	}
+	return false
+}
+
+func (mod *Module) IsSnapshotSanitizer() bool {
+	if _, ok := mod.compiler.(cc.SnapshotSanitizer); ok {
+		return true
+	}
+	return false
+}
+
 func registerRustSnapshotModules(ctx android.RegistrationContext) {
 	cc.VendorSnapshotImageSingleton.RegisterAdditionalModule(ctx,
 		"vendor_snapshot_rlib", VendorSnapshotRlibFactory)
@@ -81,6 +146,9 @@
 
 	library.SetSnapshotAndroidMkSuffix(ctx, variant)
 
+	if library.IsSanitizerEnabled(cc.Hwasan) {
+		library.properties = library.sanitizerProperties.Hwasan
+	}
 	if !library.MatchesWithDevice(ctx.DeviceConfig()) {
 		return buildOutput{}
 	}
diff --git a/rust/testing.go b/rust/testing.go
index 7f30569..3fe751e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -182,6 +182,7 @@
 	ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
 	ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
 	ctx.RegisterModuleType("rust_fuzz", RustFuzzFactory)
+	ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
 	ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
 	ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
 	ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 387d170..1e7e7d3 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -1063,7 +1063,7 @@
 		}
 	}
 
-	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkSharedLibs
+	libclientAndroidMkSharedLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList()
 	if g, w := libclientAndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib64", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient AndroidMkSharedLibs %q, got %q", w, g)
 	}
@@ -1078,7 +1078,7 @@
 		t.Errorf("wanted libclient libclientAndroidMkDylibs %q, got %q", w, libclientAndroidMkDylibs)
 	}
 
-	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).Properties.AndroidMkSharedLibs
+	libclient32AndroidMkSharedLibs := ctx.ModuleForTests("libclient", shared32Variant).Module().(*Module).transitiveAndroidMkSharedLibs.ToList()
 	if g, w := libclient32AndroidMkSharedLibs, []string{"libvndk.vendor", "libvendor_available.vendor", "lib32", "liblog.vendor", "libc.vendor", "libm.vendor", "libdl.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient32 AndroidMkSharedLibs %q, got %q", w, g)
 	}
diff --git a/scripts/check_target_sdk_less_than_30.py b/scripts/check_target_sdk_less_than_30.py
new file mode 100755
index 0000000..69b0bf0
--- /dev/null
+++ b/scripts/check_target_sdk_less_than_30.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+import subprocess
+import argparse
+import re
+import sys
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('aapt2', help = "the path to the aapt2 executable")
+    parser.add_argument('apk', help = "the apk to check")
+    parser.add_argument('stampfile', help = "a file to touch if successful")
+    args = parser.parse_args()
+
+    regex = re.compile(r"targetSdkVersion: *'([0-9]+)'")
+    output = subprocess.check_output([args.aapt2, "dump", "badging", args.apk], text=True)
+    targetSdkVersion = None
+    for line in output.splitlines():
+        match = regex.fullmatch(line.strip())
+        if match:
+            targetSdkVersion = int(match.group(1))
+            break
+
+    if targetSdkVersion is None or targetSdkVersion >= 30:
+        sys.exit(args.apk + ": Prebuilt, presigned apks with targetSdkVersion >= 30 (or a codename targetSdkVersion) must set preprocessed: true in the Android.bp definition (because they must be signed with signature v2, and the build system would wreck that signature otherwise)")
+
+    subprocess.check_call(["touch", args.stampfile])
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 3ac1b7e..c6aa3d0 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -120,6 +120,37 @@
         f.write(pb.SerializeToString())
 
 
+def Validate(args):
+    if os.path.isdir(args.input):
+        config_file = os.path.join(args.input, 'etc/linker.config.pb')
+        if os.path.exists(config_file):
+            args.input = config_file
+            Validate(args)
+        # OK if there's no linker config file.
+        return
+
+    if not os.path.isfile(args.input):
+        sys.exit(f"{args.input} is not a file")
+
+    pb = linker_config_pb2.LinkerConfig()
+    with open(args.input, 'rb') as f:
+        pb.ParseFromString(f.read())
+
+    if args.type == 'apex':
+        # Shouldn't use provideLibs/requireLibs in APEX linker.config.pb
+        if getattr(pb, 'provideLibs'):
+            sys.exit(f'{args.input}: provideLibs is set. Use provideSharedLibs in apex_manifest')
+        if getattr(pb, 'requireLibs'):
+            sys.exit(f'{args.input}: requireLibs is set. Use requireSharedLibs in apex_manifest')
+    elif args.type == 'system':
+        if getattr(pb, 'visible'):
+            sys.exit(f'{args.input}: do not use visible, which is for APEX')
+        if getattr(pb, 'permittedPaths'):
+            sys.exit(f'{args.input}: do not use permittedPaths, which is for APEX')
+    else:
+        sys.exit(f'Unknown type: {args.type}')
+
+
 def GetArgParser():
     parser = argparse.ArgumentParser()
     subparsers = parser.add_subparsers()
@@ -227,6 +258,18 @@
         help='Linker configuration files to merge.')
     append.set_defaults(func=Merge)
 
+    validate = subparsers.add_parser('validate', help='Validate configuration')
+    validate.add_argument(
+        '--type',
+        required=True,
+        choices=['apex', 'system'],
+        help='Type of linker configuration')
+    validate.add_argument(
+        'input',
+        help='Input can be a directory which has etc/linker.config.pb or a path'
+        ' to the linker config file')
+    validate.set_defaults(func=Validate)
+
     return parser
 
 
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
index 86b4aa3..6ef01eb 100755
--- a/scripts/mkcratersp.py
+++ b/scripts/mkcratersp.py
@@ -48,6 +48,8 @@
     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] == '-':
@@ -64,9 +66,13 @@
 create_archive(f'{out}.a', [], temp_archives)
 
 with open(out, 'w') as f:
-  print(f'-Wl,--whole-archive', file=f)
-  print(f'{out}.whole.a', file=f)
-  print(f'-Wl,--no-whole-archive', file=f)
+  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)
diff --git a/scripts/prepare-moved-top.sh b/scripts/prepare-moved-top.sh
new file mode 100755
index 0000000..d941529
--- /dev/null
+++ b/scripts/prepare-moved-top.sh
@@ -0,0 +1,41 @@
+#!/bin/bash -eu
+
+###############
+# Removes the Bazel output base and ninja file.
+# This is intended to solve an issue when a build top is moved.
+# Starlark symlinks are absolute and a moved build top will have many
+# dangling symlinks and fail to function as intended.
+# If the bazel output base is removed WITHOUT the top moving,
+# then any subsequent builds will fail as soong_build will not rerun.
+# Removing the ninja file will force a re-execution.
+#
+# You MUST lunch again after moving your build top, before running this.
+###############
+
+if [[ ! -v ANDROID_BUILD_TOP ]]; then
+    echo "ANDROID_BUILD_TOP not found in environment. Please run lunch before running this script"
+    exit 1
+fi
+
+if [[ ! -v OUT_DIR ]]; then
+    out_dir="$ANDROID_BUILD_TOP/out"
+else
+    out_dir="$ANDROID_BUILD_TOP/$OUT_DIR"
+fi
+
+output_base=$out_dir/bazel/output/
+ninja_file=$out_dir/soong/build*ninja
+
+if [[ ! -d $output_base ]]; then
+    echo "The specified output directory doesn't exist."
+    echo "Have you rerun lunch since moving directories?"
+    exit 1
+fi
+
+read -p "Are you sure you want to remove $output_base and the ninja file $ninja_file? Y/N " -n 1 -r
+echo
+if [[ $REPLY =~ ^[Yy]$ ]]
+then
+   rm -rf $output_base
+   rm $ninja_file
+fi
diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go
index 7ccc114..3c0b8ae 100644
--- a/sdk/systemserverclasspath_fragment_sdk_test.go
+++ b/sdk/systemserverclasspath_fragment_sdk_test.go
@@ -86,6 +86,98 @@
 	)
 }
 
+func TestSnapshotWithPartialSystemServerClasspathFragment(t *testing.T) {
+	commonSdk := `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			min_sdk_version: "Tiramisu",
+			systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
+		}
+		systemserverclasspath_fragment {
+			name: "mysystemserverclasspathfragment",
+			apex_available: ["myapex"],
+			contents: [
+				"mysdklibrary",
+				"mysdklibrary-future",
+			],
+		}
+		java_sdk_library {
+			name: "mysdklibrary",
+			apex_available: ["myapex"],
+			srcs: ["Test.java"],
+			min_sdk_version: "33", // Tiramisu
+		}
+		java_sdk_library {
+			name: "mysdklibrary-future",
+			apex_available: ["myapex"],
+			srcs: ["Test.java"],
+			min_sdk_version: "34", // UpsideDownCake
+		}
+		sdk {
+			name: "mysdk",
+			apexes: ["myapex"],
+		}
+	`
+
+	result := android.GroupFixturePreparers(
+		prepareForSdkTestWithJava,
+		java.PrepareForTestWithJavaDefaultModules,
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("mysdklibrary", "mysdklibrary-future"),
+		dexpreopt.FixtureSetApexSystemServerJars("myapex:mysdklibrary", "myapex:mysdklibrary-future"),
+		android.FixtureModifyEnv(func(env map[string]string) {
+			// targeting Tiramisu here means that we won't export mysdklibrary-future
+			env["SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE"] = "Tiramisu"
+		}),
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.Platform_version_active_codenames = []string{"UpsideDownCake"}
+		}),
+		prepareForSdkTestWithApex,
+		android.FixtureWithRootAndroidBp(commonSdk),
+	).RunTest(t)
+
+	CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(
+		`// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdklibrary",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    shared_library: true,
+    public: {
+        jars: ["sdk_library/public/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/public/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/public/mysdklibrary.txt",
+        removed_api: "sdk_library/public/mysdklibrary-removed.txt",
+        sdk_version: "current",
+    },
+    system: {
+        jars: ["sdk_library/system/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/system/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/system/mysdklibrary.txt",
+        removed_api: "sdk_library/system/mysdklibrary-removed.txt",
+        sdk_version: "system_current",
+    },
+    test: {
+        jars: ["sdk_library/test/mysdklibrary-stubs.jar"],
+        stub_srcs: ["sdk_library/test/mysdklibrary_stub_sources"],
+        current_api: "sdk_library/test/mysdklibrary.txt",
+        removed_api: "sdk_library/test/mysdklibrary-removed.txt",
+        sdk_version: "test_current",
+    },
+}
+
+prebuilt_systemserverclasspath_fragment {
+    name: "mysystemserverclasspathfragment",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    apex_available: ["myapex"],
+    contents: ["mysdklibrary"],
+} `))
+}
+
 func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) {
 	commonSdk := `
 		apex {
diff --git a/sh/Android.bp b/sh/Android.bp
index f9198dc..1deedc7 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -10,6 +10,7 @@
         "soong",
         "soong-android",
         "soong-cc",
+        "soong-java",
         "soong-tradefed",
     ],
     srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index d2eede6..00794cd 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -143,6 +143,9 @@
 	// Only available for host sh_test modules.
 	Data_device_libs []string `android:"path,arch_variant"`
 
+	// list of java modules that provide data that should be installed alongside the test.
+	Java_data []string
+
 	// Install the test into a folder named for the module in all test suites.
 	Per_testcase_directory *bool
 
@@ -307,6 +310,7 @@
 	shTestDataLibsTag       = dependencyTag{name: "dataLibs"}
 	shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
 	shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"}
+	shTestJavaDataTag       = dependencyTag{name: "javaData"}
 )
 
 var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}}
@@ -322,6 +326,10 @@
 		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
 		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
 			shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
+
+		javaDataVariation := []blueprint.Variation{{"arch", android.Common.String()}}
+		ctx.AddVariationDependencies(javaDataVariation, shTestJavaDataTag, s.testProperties.Java_data...)
+
 	} else if ctx.Target().Os.Class != android.Host {
 		if len(s.testProperties.Data_device_bins) > 0 {
 			ctx.PropertyErrorf("data_device_bins", "only available for host modules")
@@ -329,6 +337,9 @@
 		if len(s.testProperties.Data_device_libs) > 0 {
 			ctx.PropertyErrorf("data_device_libs", "only available for host modules")
 		}
+		if len(s.testProperties.Java_data) > 0 {
+			ctx.PropertyErrorf("Java_data", "only available for host modules")
+		}
 	}
 }
 
@@ -361,7 +372,13 @@
 	}
 	s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
 
-	s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
+	expandedData := android.PathsForModuleSrc(ctx, s.testProperties.Data)
+
+	// Emulate the data property for java_data dependencies.
+	for _, javaData := range ctx.GetDirectDepsWithTag(shTestJavaDataTag) {
+		expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...)
+	}
+	s.data = expandedData
 
 	var configs []tradefed.Config
 	if Bool(s.testProperties.Require_root) {
@@ -502,7 +519,7 @@
 // sh_test defines a shell script based test module.
 func ShTestFactory() android.Module {
 	module := &ShTest{}
-	initShBinaryModule(&module.ShBinary, false)
+	initShBinaryModule(&module.ShBinary, true)
 	module.AddProperties(&module.testProperties)
 
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
@@ -512,7 +529,7 @@
 // sh_test_host defines a shell script based test module that runs on a host.
 func ShTestHostFactory() android.Module {
 	module := &ShTest{}
-	initShBinaryModule(&module.ShBinary, false)
+	initShBinaryModule(&module.ShBinary, true)
 	module.AddProperties(&module.testProperties)
 	// Default sh_test_host to unit_tests = true
 	if module.testProperties.Test_options.Unit_test == nil {
@@ -548,6 +565,15 @@
 	// visibility
 }
 
+type bazelShTestAttributes struct {
+	Srcs                 bazel.LabelListAttribute
+	Data                 bazel.LabelListAttribute
+	Tags                 bazel.StringListAttribute
+	Test_config          *string
+	Test_config_template *string
+	Auto_gen_config      *bool
+}
+
 func (m *ShBinary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
 		android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}))
@@ -576,6 +602,41 @@
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
 }
 
+func (m *ShTest) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+	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...)
+
+	data := bazel.MakeLabelListAttribute(
+		android.BazelLabelForModuleSrc(ctx, combinedData))
+
+	tags := bazel.MakeStringListAttribute(
+		m.testProperties.Test_options.Tags)
+
+	test_config := m.testProperties.Test_config
+
+	test_config_template := m.testProperties.Test_config_template
+
+	auto_gen_config := m.testProperties.Auto_gen_config
+
+	attrs := &bazelShTestAttributes{
+		Srcs:                 srcs,
+		Data:                 data,
+		Tags:                 tags,
+		Test_config:          test_config,
+		Test_config_template: test_config_template,
+		Auto_gen_config:      auto_gen_config,
+	}
+
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "sh_test",
+		Bzl_load_location: "//build/bazel/rules:sh_test.bzl",
+	}
+	ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
+}
+
 var Bool = proptools.Bool
 
 var _ snapshot.RelativeInstallPath = (*ShBinary)(nil)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 89b8126..5fcb58d 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -9,6 +9,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/java"
 )
 
 func TestMain(m *testing.M) {
@@ -17,6 +18,7 @@
 
 var prepareForShTest = android.GroupFixturePreparers(
 	cc.PrepareForTestWithCcBuildComponents,
+	java.PrepareForTestWithJavaDefaultModules,
 	PrepareForTestWithShBuildComponents,
 	android.FixtureMergeMockFs(android.MockFS{
 		"test.sh":            nil,
@@ -255,3 +257,39 @@
 		t.Errorf("foo extraConfings %v does not contain %q", autogen.Args["extraConfigs"], expectedBinAutogenConfig)
 	}
 }
+
+func TestShTestHost_javaData(t *testing.T) {
+	ctx, config := testShBinary(t, `
+		sh_test_host {
+			name: "foo",
+			src: "test.sh",
+			filename: "test.sh",
+			data: [
+				"testdata/data1",
+				"testdata/sub/data2",
+			],
+			java_data: [
+				"javalib",
+			],
+		}
+
+		java_library_host {
+			name: "javalib",
+			srcs: [],
+		}
+	`)
+	buildOS := ctx.Config().BuildOS.String()
+	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
+	if !mod.Host() {
+		t.Errorf("host bit is not set for a sh_test_host module.")
+	}
+	expectedData := []string{
+		":testdata/data1",
+		":testdata/sub/data2",
+		"out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar",
+	}
+
+	entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+	actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
+}
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index 4209507..0224bcf 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"reflect"
 	"sort"
 	"strconv"
 	"strings"
@@ -33,6 +34,72 @@
 	return strings.Repeat(" ", level*indent)
 }
 
+func PrintAny(value any, indentLevel int) string {
+	return printAnyRecursive(reflect.ValueOf(value), indentLevel)
+}
+
+func printAnyRecursive(value reflect.Value, indentLevel int) string {
+	switch value.Type().Kind() {
+	case reflect.String:
+		val := value.String()
+		if strings.Contains(val, "\"") || strings.Contains(val, "\n") {
+			return `'''` + val + `'''`
+		}
+		return `"` + val + `"`
+	case reflect.Bool:
+		if value.Bool() {
+			return "True"
+		} else {
+			return "False"
+		}
+	case reflect.Int:
+		return fmt.Sprintf("%d", value.Int())
+	case reflect.Slice:
+		if value.Len() == 0 {
+			return "[]"
+		} else if value.Len() == 1 {
+			return "[" + printAnyRecursive(value.Index(0), indentLevel) + "]"
+		}
+		list := make([]string, 0, value.Len()+2)
+		list = append(list, "[")
+		innerIndent := Indention(indentLevel + 1)
+		for i := 0; i < value.Len(); i++ {
+			list = append(list, innerIndent+printAnyRecursive(value.Index(i), indentLevel+1)+`,`)
+		}
+		list = append(list, Indention(indentLevel)+"]")
+		return strings.Join(list, "\n")
+	case reflect.Map:
+		if value.Len() == 0 {
+			return "{}"
+		}
+		items := make([]string, 0, value.Len())
+		for _, key := range value.MapKeys() {
+			items = append(items, fmt.Sprintf(`%s%s: %s,`, Indention(indentLevel+1), printAnyRecursive(key, indentLevel+1), printAnyRecursive(value.MapIndex(key), indentLevel+1)))
+		}
+		sort.Strings(items)
+		return fmt.Sprintf(`{
+%s
+%s}`, strings.Join(items, "\n"), Indention(indentLevel))
+	case reflect.Struct:
+		if value.NumField() == 0 {
+			return "struct()"
+		}
+		items := make([]string, 0, value.NumField()+2)
+		items = append(items, "struct(")
+		for i := 0; i < value.NumField(); i++ {
+			if value.Type().Field(i).Anonymous {
+				panic("anonymous fields aren't supported")
+			}
+			name := value.Type().Field(i).Name
+			items = append(items, fmt.Sprintf(`%s%s = %s,`, Indention(indentLevel+1), name, printAnyRecursive(value.Field(i), indentLevel+1)))
+		}
+		items = append(items, Indention(indentLevel)+")")
+		return strings.Join(items, "\n")
+	default:
+		panic("Unhandled kind: " + value.Kind().String())
+	}
+}
+
 // PrintBool returns a Starlark compatible bool string.
 func PrintBool(item bool) string {
 	if item {
diff --git a/starlark_import/unmarshal.go b/starlark_import/unmarshal.go
index 33c0cd9..b243471 100644
--- a/starlark_import/unmarshal.go
+++ b/starlark_import/unmarshal.go
@@ -34,6 +34,9 @@
 		return reflect.ValueOf(value), nil
 	}
 	zero := reflect.Zero(ty)
+	if value == nil {
+		panic("nil value")
+	}
 	var result reflect.Value
 	if ty.Kind() == reflect.Interface {
 		var err error
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 0edbb7c..a2c0fb7 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -24,6 +24,7 @@
 	"sync"
 
 	"android/soong/bazel"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -410,7 +411,7 @@
 	Apex_available     []string
 	Min_sdk_version    *string
 	Bazel_module       struct {
-		Bp2build_available *bool
+		Label *string
 	}
 }
 
@@ -428,6 +429,9 @@
 	SyspropPublicStub string
 	Apex_available    []string
 	Min_sdk_version   *string
+	Bazel_module      struct {
+		Bp2build_available *bool
+	}
 }
 
 func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
@@ -473,6 +477,14 @@
 			"Unknown value %s: must be one of Platform, Vendor or Odm", m.Owner())
 	}
 
+	var label *string
+	if b, ok := ctx.Module().(android.Bazelable); ok && b.ShouldConvertWithBp2build(ctx) {
+		// TODO: b/295566168 - this will need to change once build files are checked in to account for
+		// checked in modules in mixed builds
+		label = proptools.StringPtr(
+			fmt.Sprintf("//%s:%s", ctx.ModuleDir(), m.CcImplementationModuleName()))
+	}
+
 	// Generate a C++ implementation library.
 	// cc_library can receive *.sysprop files as their srcs, generating sources itself.
 	ccProps := ccLibraryProperties{}
@@ -492,11 +504,7 @@
 	ccProps.Host_supported = m.properties.Host_supported
 	ccProps.Apex_available = m.ApexProperties.Apex_available
 	ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
-	// A Bazel macro handles this, so this module does not need to be handled
-	// in bp2build
-	// TODO(b/237810289) perhaps do something different here so that we aren't
-	//                   also disabling these modules in mixed builds
-	ccProps.Bazel_module.Bp2build_available = proptools.BoolPtr(false)
+	ccProps.Bazel_module.Label = label
 	ctx.CreateModule(cc.LibraryFactory, &ccProps)
 
 	scope := "internal"
@@ -541,6 +549,11 @@
 		SyspropPublicStub: publicStub,
 		Apex_available:    m.ApexProperties.Apex_available,
 		Min_sdk_version:   m.properties.Java.Min_sdk_version,
+		Bazel_module: struct {
+			Bp2build_available *bool
+		}{
+			Bp2build_available: proptools.BoolPtr(false),
+		},
 	})
 
 	if publicStub != "" {
@@ -558,6 +571,11 @@
 			Sdk_version: proptools.StringPtr("core_current"),
 			Libs:        []string{javaSyspropStub},
 			Stem:        proptools.StringPtr(m.BaseModuleName()),
+			Bazel_module: struct {
+				Bp2build_available *bool
+			}{
+				Bp2build_available: proptools.BoolPtr(false),
+			},
 		})
 	}
 
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 090114b..c866265 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -330,6 +330,12 @@
   if [[ -L "./out/soong/workspace/foo/F2D" ]] || [[ ! -d "./out/soong/workspace/foo/F2D" ]]; then
     fail "./out/soong/workspace/foo/F2D should be a dir"
   fi
+
+  # relative symlinks
+  local BAZEL_BIN_RELATIVE_SYMLINK=`readlink out/soong/workspace/build/bazel/bin`
+  if [[ $BAZEL_BIN_RELATIVE_SYMLINK != "../../../../../build/bazel/bin" ]]; then
+    fail "out/soong/workspace/build/bazel/bin should be a relative symlink"
+  fi
 }
 
 function test_cc_correctness {
@@ -407,38 +413,6 @@
   fi
 }
 
-# Smoke test to verify api_bp2build worksapce does not contain any errors
-function test_api_bp2build_empty_build() {
-  setup
-  run_soong api_bp2build
-  run_bazel build --config=android --config=api_bp2build //:empty
-}
-
-# Verify that an *_api_contribution target can refer to an api file from
-# another Bazel package.
-function test_api_export_from_another_bazel_package() {
-  setup
-  # Parent dir Android.bp
-  mkdir -p foo
-  cat > foo/Android.bp << 'EOF'
-cc_library {
-  name: "libfoo",
-  stubs: {
-    symbol_file: "api/libfoo.map.txt",
-  },
-}
-EOF
-  # Child dir Android.bp
-  mkdir -p foo/api
-  cat > foo/api/Android.bp << 'EOF'
-package{}
-EOF
-  touch foo/api/libfoo.map.txt
-  # Run test
-  run_soong api_bp2build
-  run_bazel build --config=android --config=api_bp2build //foo:libfoo.contribution
-}
-
 function test_bazel_standalone_output_paths_contain_product_name {
   setup
   mkdir -p a
diff --git a/tests/lib.sh b/tests/lib.sh
index 40b317b..d934470 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,10 +8,15 @@
 
 REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 
+function make_mock_top {
+  mock=$(mktemp -t -d st.XXXXX)
+  echo "$mock"
+}
+
 if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
   MOCK_TOP="$HARDWIRED_MOCK_TOP"
 else
-  MOCK_TOP=$(mktemp -t -d st.XXXXX)
+  MOCK_TOP=$(make_mock_top)
   trap cleanup_mock_top EXIT
 fi
 
@@ -52,6 +57,10 @@
   cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
 }
 
+function delete_directory {
+  rm -rf "$MOCK_TOP/$1"
+}
+
 function symlink_file {
   local file="$1"
 
@@ -138,6 +147,9 @@
   copy_directory build/bazel
   copy_directory build/bazel_common_rules
 
+  # This requires pulling more tools into the mock top to build partitions
+  delete_directory build/bazel/examples/partitions
+
   symlink_directory packages/modules/common/build
   symlink_directory prebuilts/bazel
   symlink_directory prebuilts/clang
@@ -147,7 +159,11 @@
   symlink_directory external/bazelbuild-rules_go
   symlink_directory external/bazelbuild-rules_license
   symlink_directory external/bazelbuild-kotlin-rules
+  symlink_directory external/bazelbuild-rules_cc
+  symlink_directory external/bazelbuild-rules_python
   symlink_directory external/bazelbuild-rules_java
+  symlink_directory external/bazelbuild-rules_rust
+  symlink_directory external/rust/crates/tinyjson
 
   symlink_file WORKSPACE
   symlink_file BUILD
@@ -186,3 +202,10 @@
     info "Completed test case \e[96;1m$f\e[0m"
   done
 }
+
+function move_mock_top {
+  MOCK_TOP2=$(make_mock_top)
+  mv $MOCK_TOP $MOCK_TOP2
+  MOCK_TOP=$MOCK_TOP2
+  trap cleanup_mock_top EXIT
+}
diff --git a/tests/relative_symlinks_test.sh b/tests/relative_symlinks_test.sh
new file mode 100755
index 0000000..9477f8c
--- /dev/null
+++ b/tests/relative_symlinks_test.sh
@@ -0,0 +1,90 @@
+#!/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 test_movable_top_bazel_build {
+  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)
+
+  move_mock_top
+
+  # remove the bazel output base
+  rm -rf $outdir/bazel/output_user_root
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+}
+
+function test_movable_top_soong_build {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+}
+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 g)
+
+  move_mock_top
+
+  # remove the bazel output base
+  rm -rf $outdir/bazel/output
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong g)
+}
+
+function test_remove_output_base_and_ninja_file {
+  # If the bazel output base is removed without the ninja file, the build will fail
+  # This tests that removing both the bazel output base and ninja file will succeed
+  # without a clean
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+}
+EOF
+  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 g)
+  # remove the bazel output base
+  rm -rf $outdir/bazel/output
+  rm $outdir/soong/build*ninja
+
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong g)
+}
+
+scan_and_run_tests
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 48f654e..5789f52 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -22,7 +22,6 @@
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
 
-"$TOP/build/soong/tests/sbom_test.sh"
-
 "$TOP/build/bazel/ci/b_test.sh"
+"$TOP/build/soong/tests/relative_symlinks_test.sh"
 
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index afec6b1..73fbeab 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -47,13 +47,10 @@
 }
 
 function diff_files {
-  file_list_file="$1"; shift
-  files_in_spdx_file="$1"; shift
-  partition_name="$1"; shift
-  exclude=
-  if [ -v 'diff_excludes[$partition_name]' ]; then
-   exclude=${diff_excludes[$partition_name]}
-  fi
+  local file_list_file="$1"; shift
+  local files_in_spdx_file="$1"; shift
+  local partition_name="$1"; shift
+  local exclude="$1"; shift
 
   diff "$file_list_file" "$files_in_spdx_file" $exclude
   if [ $? != "0" ]; then
@@ -84,68 +81,6 @@
   dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs
   lz4=$out_dir/host/linux-x86/bin/lz4
 
-  declare -A diff_excludes
-  diff_excludes[product]="\
-    -I /product/etc/aconfig_flags.textproto \
-    -I /product/etc/build_flags.json"
-  diff_excludes[vendor]="\
-    -I /vendor/lib64/libkeystore2_crypto.so \
-    -I /vendor/etc/aconfig_flags.textproto \
-    -I /vendor/etc/build_flags.json"
-  diff_excludes[system]="\
-    -I /bin \
-    -I /bugreports \
-    -I /cache \
-    -I /d \
-    -I /etc \
-    -I /init \
-    -I /odm/app \
-    -I /odm/bin \
-    -I /odm_dlkm/etc \
-    -I /odm/etc \
-    -I /odm/firmware \
-    -I /odm/framework \
-    -I /odm/lib \
-    -I /odm/lib64 \
-    -I /odm/overlay \
-    -I /odm/priv-app \
-    -I /odm/usr \
-    -I /sdcard \
-    -I /system/etc/aconfig_flags.textproto \
-    -I /system/etc/build_flags.json \
-    -I /system/lib64/android.hardware.confirmationui@1.0.so \
-    -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
-    -I /system/lib64/android.hardware.keymaster@4.1.so \
-    -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \
-    -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
-    -I /system/lib64/android.security.compat-ndk.so \
-    -I /system/lib64/libcuttlefish_allocd_utils.so \
-    -I /system/lib64/libcuttlefish_device_config_proto.so \
-    -I /system/lib64/libcuttlefish_device_config.so \
-    -I /system/lib64/libcuttlefish_fs.so \
-    -I /system/lib64/libcuttlefish_kernel_log_monitor_utils.so \
-    -I /system/lib64/libcuttlefish_utils.so \
-    -I /system/lib64/libfruit.so \
-    -I /system/lib64/libgflags.so \
-    -I /system/lib64/libkeymaster4_1support.so \
-    -I /system/lib64/libkeymaster4support.so \
-    -I /system/lib64/libkeymint.so \
-    -I /system/lib64/libkeystore2_aaid.so \
-    -I /system/lib64/libkeystore2_apc_compat.so \
-    -I /system/lib64/libkeystore2_crypto.so \
-    -I /system/lib64/libkeystore-attestation-application-id.so \
-    -I /system/lib64/libkm_compat_service.so \
-    -I /system/lib64/libkm_compat.so \
-    -I /system/lib64/vndk-29 \
-    -I /system/lib64/vndk-sp-29 \
-    -I /system/lib/vndk-29 \
-    -I /system/lib/vndk-sp-29 \
-    -I /system/usr/icu \
-    -I /vendor_dlkm/etc"
-  diff_excludes[system_ext]="\
-    -I /system_ext/etc/aconfig_flags.textproto \
-    -I /system_ext/etc/build_flags.json"
-
   # Example output of dump.erofs is as below, and the data used in the test start
   # at line 11. Column 1 is inode id, column 2 is inode type and column 3 is name.
   # Each line is captured in variable "entry", awk is used to get type and name.
@@ -217,7 +152,7 @@
     sort -n -o "$files_in_spdx_file" "$files_in_spdx_file"
 
     echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
+    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
   done
 
   RAMDISK_IMAGES="$product_out/ramdisk.img"
@@ -235,13 +170,48 @@
     grep "FileName: /${partition_name}/" $product_out/sbom.spdx | sed 's/^FileName: //' | sort -n > "$files_in_spdx_file"
 
     echo ============ Diffing files in $f and SBOM
-    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
+    diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name" ""
   done
 
+  verify_package_verification_code "$product_out/sbom.spdx"
+
   # Teardown
   cleanup "${out_dir}"
 }
 
+function verify_package_verification_code {
+  local sbom_file="$1"; shift
+
+  local -a file_checksums
+  local package_product_found=
+  while read -r line;
+  do
+    if grep -q 'PackageVerificationCode' <<<"$line"
+    then
+      package_product_found=true
+    fi
+    if [ -n "$package_product_found" ]
+    then
+      if grep -q 'FileChecksum' <<< "$line"
+      then
+        checksum=$(echo $line | sed 's/^.*: //')
+        file_checksums+=("$checksum")
+      fi
+    fi
+  done <<< "$(grep -E 'PackageVerificationCode|FileChecksum' $sbom_file)"
+  IFS=$'\n' file_checksums=($(sort <<<"${file_checksums[*]}")); unset IFS
+  IFS= expected_package_verification_code=$(printf "${file_checksums[*]}" | sha1sum | sed 's/[[:space:]]*-//'); unset IFS
+
+  actual_package_verification_code=$(grep PackageVerificationCode $sbom_file | sed 's/PackageVerificationCode: //g')
+  if [ $actual_package_verification_code = $expected_package_verification_code ]
+  then
+    echo "Package verification code is correct."
+  else
+    echo "Unexpected package verification code."
+    exit 1
+  fi
+}
+
 function test_sbom_unbundled_apex {
   # Setup
   out_dir="$(setup)"
diff --git a/third_party/zip/android.go b/third_party/zip/android.go
index 0f41f62..b972156 100644
--- a/third_party/zip/android.go
+++ b/third_party/zip/android.go
@@ -56,6 +56,11 @@
 	if err := writeHeader(w.cw, fh); err != nil {
 		return err
 	}
+
+	// Strip the extras again in case writeHeader added the local file header extras that are incorrect for the
+	// central directory.
+	fh.Extra = stripExtras(fh.Extra)
+
 	dataOffset, err := orig.DataOffset()
 	if err != nil {
 		return err
diff --git a/tradefed/autogen_bazel.go b/tradefed/autogen_bazel.go
index d3109d9..8283984 100644
--- a/tradefed/autogen_bazel.go
+++ b/tradefed/autogen_bazel.go
@@ -39,7 +39,8 @@
 )
 
 type TestConfigAttributes struct {
-	Test_config *bazel.Label
+	Test_config    *bazel.Label
+	Dynamic_config *bazel.Label
 
 	Auto_generate_test_config *bool
 	Template_test_config      *bazel.Label
@@ -58,6 +59,11 @@
 	templateInstallBase *string) TestConfigAttributes {
 
 	attrs := TestConfigAttributes{}
+
+	dynamicConfig := "DynamicConfig.xml"
+	c, _ := android.BazelStringOrLabelFromProp(ctx, &dynamicConfig)
+	attrs.Dynamic_config = c.Value
+
 	attrs.Test_config = GetTestConfig(ctx, testConfig)
 	// do not generate a test config if
 	// 1) test config already found
@@ -99,7 +105,7 @@
 	}
 
 	// check for default AndroidTest.xml
-	defaultTestConfigPath := ctx.ModuleDir() + "/AndroidTest.xml"
+	defaultTestConfigPath := "AndroidTest.xml"
 	c, _ := android.BazelStringOrLabelFromProp(ctx, &defaultTestConfigPath)
 	return c.Value
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index fb5f7dd..084d28d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,7 +15,6 @@
 package build
 
 import (
-	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -40,9 +39,6 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
-
-	configFetcher         = "vendor/google/tools/soong/expconfigfetcher"
-	envConfigFetchTimeout = 20 * time.Second
 )
 
 var (
@@ -74,7 +70,6 @@
 	checkbuild               bool
 	dist                     bool
 	jsonModuleGraph          bool
-	apiBp2build              bool // Generate BUILD files for Soong modules that contribute APIs
 	bp2build                 bool
 	queryview                bool
 	reportMkMetrics          bool // Collect and report mk2bp migration progress metrics.
@@ -174,87 +169,6 @@
 	}
 }
 
-// fetchEnvConfig optionally fetches a configuration file that can then subsequently be
-// loaded into Soong environment to control certain aspects of build behavior (e.g., enabling RBE).
-// If a configuration file already exists on disk, the fetch is run in the background
-// so as to NOT block the rest of the build execution.
-func fetchEnvConfig(ctx Context, config *configImpl, envConfigName string) error {
-	configName := envConfigName + "." + jsonSuffix
-	expConfigFetcher := &smpb.ExpConfigFetcher{Filename: &configName}
-	defer func() {
-		ctx.Metrics.ExpConfigFetcher(expConfigFetcher)
-	}()
-	if !config.GoogleProdCredsExist() {
-		status := smpb.ExpConfigFetcher_MISSING_GCERT
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	s, err := os.Stat(configFetcher)
-	if err != nil {
-		if os.IsNotExist(err) {
-			return nil
-		}
-		return err
-	}
-	if s.Mode()&0111 == 0 {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return fmt.Errorf("configuration fetcher binary %v is not executable: %v", configFetcher, s.Mode())
-	}
-
-	configExists := false
-	outConfigFilePath := filepath.Join(config.OutDir(), configName)
-	if _, err := os.Stat(outConfigFilePath); err == nil {
-		configExists = true
-	}
-
-	tCtx, cancel := context.WithTimeout(ctx, envConfigFetchTimeout)
-	fetchStart := time.Now()
-	cmd := exec.CommandContext(tCtx, configFetcher, "-output_config_dir", config.OutDir(),
-		"-output_config_name", configName)
-	if err := cmd.Start(); err != nil {
-		status := smpb.ExpConfigFetcher_ERROR
-		expConfigFetcher.Status = &status
-		return err
-	}
-
-	fetchCfg := func() error {
-		if err := cmd.Wait(); err != nil {
-			status := smpb.ExpConfigFetcher_ERROR
-			expConfigFetcher.Status = &status
-			return err
-		}
-		fetchEnd := time.Now()
-		expConfigFetcher.Micros = proto.Uint64(uint64(fetchEnd.Sub(fetchStart).Microseconds()))
-		expConfigFetcher.Filename = proto.String(outConfigFilePath)
-
-		if _, err := os.Stat(outConfigFilePath); err != nil {
-			status := smpb.ExpConfigFetcher_NO_CONFIG
-			expConfigFetcher.Status = &status
-			return err
-		}
-		status := smpb.ExpConfigFetcher_CONFIG
-		expConfigFetcher.Status = &status
-		return nil
-	}
-
-	// If a config file does not exist, wait for the config file to be fetched. Otherwise
-	// fetch the config file in the background and return immediately.
-	if !configExists {
-		defer cancel()
-		return fetchCfg()
-	}
-
-	go func() {
-		defer cancel()
-		if err := fetchCfg(); err != nil {
-			ctx.Verbosef("Failed to fetch config file %v: %v\n", configName, err)
-		}
-	}()
-	return nil
-}
-
 func loadEnvConfig(ctx Context, config *configImpl, bc string) error {
 	if bc == "" {
 		return nil
@@ -368,12 +282,14 @@
 	bc := os.Getenv("ANDROID_BUILD_ENVIRONMENT_CONFIG")
 
 	if bc != "" {
-		if err := fetchEnvConfig(ctx, ret, bc); err != nil {
-			ctx.Verbosef("Failed to fetch config file: %v\n", err)
-		}
 		if err := loadEnvConfig(ctx, ret, bc); err != nil {
 			ctx.Fatalln("Failed to parse env config files: %v", err)
 		}
+		if !ret.canSupportRBE() {
+			// Explicitly set USE_RBE env variable to false when we cannot run
+			// an RBE build to avoid ninja local execution pool issues.
+			ret.environ.Set("USE_RBE", "false")
+		}
 	}
 
 	if distDir, ok := ret.environ.Get("DIST_DIR"); ok {
@@ -520,6 +436,11 @@
 	ret.environ.Set("ANDROID_JAVA11_HOME", java11Home)
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
+	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
+	// to unzip to enable zipbomb detection that incorrectly handle zip64 and data descriptors and fail on large
+	// zip files produced by soong_zip.  Disable zipbomb detection.
+	ret.environ.Set("UNZIP_DISABLE_ZIPBOMB_DETECTION", "TRUE")
+
 	if ret.MultitreeBuild() {
 		ret.environ.Set("MULTITREE_BUILD", "true")
 	}
@@ -947,8 +868,6 @@
 			c.jsonModuleGraph = true
 		} else if arg == "bp2build" {
 			c.bp2build = true
-		} else if arg == "api_bp2build" {
-			c.apiBp2build = true
 		} else if arg == "queryview" {
 			c.queryview = true
 		} else if arg == "soong_docs" {
@@ -1048,7 +967,7 @@
 		return true
 	}
 
-	if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() && !c.ApiBp2build() {
+	if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() {
 		// Command line was empty, the default Ninja target is built
 		return true
 	}
@@ -1146,10 +1065,6 @@
 	return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
 }
 
-func (c *configImpl) ApiBp2buildMarkerFile() string {
-	return shared.JoinPath(c.SoongOutDir(), "api_bp2build.marker")
-}
-
 func (c *configImpl) ModuleGraphFile() string {
 	return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
 }
@@ -1191,10 +1106,6 @@
 	return c.bp2build
 }
 
-func (c *configImpl) ApiBp2build() bool {
-	return c.apiBp2build
-}
-
 func (c *configImpl) Queryview() bool {
 	return c.queryview
 }
@@ -1374,18 +1285,26 @@
 	return true
 }
 
-func (c *configImpl) UseRBE() bool {
-	// These alternate modes of running Soong do not use RBE / reclient.
-	if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
-		return false
-	}
-
-	authType, _ := c.rbeAuth()
+func (c *configImpl) canSupportRBE() bool {
 	// Do not use RBE with prod credentials in scenarios when stubby doesn't exist, since
 	// its unlikely that we will be able to obtain necessary creds without stubby.
+	authType, _ := c.rbeAuth()
 	if !c.StubbyExists() && strings.Contains(authType, "use_google_prod_creds") {
 		return false
 	}
+	return true
+}
+
+func (c *configImpl) UseRBE() bool {
+	// These alternate modes of running Soong do not use RBE / reclient.
+	if c.Bp2Build() || c.Queryview() || c.JsonModuleGraph() {
+		return false
+	}
+
+	if !c.canSupportRBE() {
+		return false
+	}
+
 	if v, ok := c.Environment().Get("USE_RBE"); ok {
 		v = strings.TrimSpace(v)
 		if v != "" && v != "false" {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 61aaad8..b69e938 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -194,6 +194,10 @@
 
 			// LLVM compiler wrapper options
 			"TOOLCHAIN_RUSAGE_OUTPUT",
+
+			// We don't want this build broken flag to cause reanalysis, so allow it through to the
+			// actions.
+			"BUILD_BROKEN_INCORRECT_PARTITION_IMAGES",
 		}, config.BuildBrokenNinjaUsesEnvVars()...)...)
 	}
 
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index b3e871f..eba823a 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -87,7 +87,6 @@
 // run during the build. For more documentation, see path_interposer.go .
 var Configuration = map[string]PathConfig{
 	"bash":           Allowed,
-	"dd":             Allowed,
 	"diff":           Allowed,
 	"dlv":            Allowed,
 	"expr":           Allowed,
diff --git a/ui/build/soong.go b/ui/build/soong.go
index a4cf7fb..44c20a0 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -41,7 +41,6 @@
 	bp2buildWorkspaceTag = "bp2build_workspace"
 	jsonModuleGraphTag   = "modulegraph"
 	queryviewTag         = "queryview"
-	apiBp2buildTag       = "api_bp2build"
 	soongDocsTag         = "soong_docs"
 
 	// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
@@ -161,6 +160,14 @@
 	debugPort    string
 }
 
+func getGlobPathName(config Config) string {
+	globPathName, ok := config.TargetProductOrErr()
+	if ok != nil {
+		globPathName = soongBuildTag
+	}
+	return globPathName
+}
+
 func (pb PrimaryBuilderFactory) primaryBuilderInvocation() bootstrap.PrimaryBuilderInvocation {
 	commonArgs := make([]string, 0, 0)
 
@@ -195,9 +202,14 @@
 
 	var allArgs []string
 	allArgs = append(allArgs, pb.specificArgs...)
+	globPathName := pb.name
+	// Glob path for soong build would be separated per product target
+	if pb.name == soongBuildTag {
+		globPathName = getGlobPathName(pb.config)
+	}
 	allArgs = append(allArgs,
-		"--globListDir", pb.name,
-		"--globFile", pb.config.NamedGlobFile(pb.name))
+		"--globListDir", globPathName,
+		"--globFile", pb.config.NamedGlobFile(globPathName))
 
 	allArgs = append(allArgs, commonArgs...)
 	allArgs = append(allArgs, environmentArgs(pb.config, pb.name)...)
@@ -247,11 +259,10 @@
 
 func bootstrapGlobFileList(config Config) []string {
 	return []string{
-		config.NamedGlobFile(soongBuildTag),
+		config.NamedGlobFile(getGlobPathName(config)),
 		config.NamedGlobFile(bp2buildFilesTag),
 		config.NamedGlobFile(jsonModuleGraphTag),
 		config.NamedGlobFile(queryviewTag),
-		config.NamedGlobFile(apiBp2buildTag),
 		config.NamedGlobFile(soongDocsTag),
 	}
 }
@@ -292,9 +303,6 @@
 	}
 
 	queryviewDir := filepath.Join(config.SoongOutDir(), "queryview")
-	// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
-	// The final workspace will be generated in out/soong/api_bp2build
-	apiBp2buildDir := filepath.Join(config.SoongOutDir(), ".api_bp2build")
 
 	pbfs := []PrimaryBuilderFactory{
 		{
@@ -342,15 +350,6 @@
 			),
 		},
 		{
-			name:        apiBp2buildTag,
-			description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
-			config:      config,
-			output:      config.ApiBp2buildMarkerFile(),
-			specificArgs: append(baseArgs,
-				"--bazel_api_bp2build_dir", apiBp2buildDir,
-			),
-		},
-		{
 			name:        soongDocsTag,
 			description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
 			config:      config,
@@ -520,10 +519,6 @@
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(queryviewTag))
 		}
 
-		if config.ApiBp2build() {
-			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(apiBp2buildTag))
-		}
-
 		if config.SoongDocs() {
 			checkEnvironmentFile(ctx, soongBuildEnv, config.UsedEnvFile(soongDocsTag))
 		}
@@ -595,10 +590,6 @@
 		targets = append(targets, config.QueryviewMarkerFile())
 	}
 
-	if config.ApiBp2build() {
-		targets = append(targets, config.ApiBp2buildMarkerFile())
-	}
-
 	if config.SoongDocs() {
 		targets = append(targets, config.SoongDocsHtml())
 	}
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index fb760ac..7b25d50 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -40,10 +40,11 @@
 	}
 
 	n := &NinjaReader{
-		status: status,
-		fifo:   fifo,
-		done:   make(chan bool),
-		cancel: make(chan bool),
+		status:     status,
+		fifo:       fifo,
+		forceClose: make(chan bool),
+		done:       make(chan bool),
+		cancelOpen: make(chan bool),
 	}
 
 	go n.run()
@@ -52,10 +53,11 @@
 }
 
 type NinjaReader struct {
-	status ToolStatus
-	fifo   string
-	done   chan bool
-	cancel chan bool
+	status     ToolStatus
+	fifo       string
+	forceClose chan bool
+	done       chan bool
+	cancelOpen chan bool
 }
 
 const NINJA_READER_CLOSE_TIMEOUT = 5 * time.Second
@@ -63,18 +65,34 @@
 // Close waits for NinjaReader to finish reading from the fifo, or 5 seconds.
 func (n *NinjaReader) Close() {
 	// Signal the goroutine to stop if it is blocking opening the fifo.
-	close(n.cancel)
+	close(n.cancelOpen)
 
+	// Ninja should already have exited or been killed, wait 5 seconds for the FIFO to be closed and any
+	// remaining messages to be processed through the NinjaReader.run goroutine.
 	timeoutCh := time.After(NINJA_READER_CLOSE_TIMEOUT)
-
 	select {
 	case <-n.done:
-		// Nothing
+		return
 	case <-timeoutCh:
-		n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
+		// Channel is not closed yet
 	}
 
-	return
+	n.status.Error(fmt.Sprintf("ninja fifo didn't finish after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
+
+	// Force close the reader even if the FIFO didn't close.
+	close(n.forceClose)
+
+	// Wait again for the reader thread to acknowledge the close before giving up and assuming it isn't going
+	// to send anything else.
+	timeoutCh = time.After(NINJA_READER_CLOSE_TIMEOUT)
+	select {
+	case <-n.done:
+		return
+	case <-timeoutCh:
+		// Channel is not closed yet
+	}
+
+	n.status.Verbose(fmt.Sprintf("ninja fifo didn't finish even after force closing after %s", NINJA_READER_CLOSE_TIMEOUT.String()))
 }
 
 func (n *NinjaReader) run() {
@@ -98,7 +116,7 @@
 	select {
 	case f = <-fileCh:
 		// Nothing
-	case <-n.cancel:
+	case <-n.cancelOpen:
 		return
 	}
 
@@ -108,33 +126,58 @@
 
 	running := map[uint32]*Action{}
 
+	msgChan := make(chan *ninja_frontend.Status)
+
+	// Read from the ninja fifo and decode the protobuf in a goroutine so the main NinjaReader.run goroutine
+	// can listen
+	go func() {
+		defer close(msgChan)
+		for {
+			size, err := readVarInt(r)
+			if err != nil {
+				if err != io.EOF {
+					n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+				}
+				return
+			}
+
+			buf := make([]byte, size)
+			_, err = io.ReadFull(r, buf)
+			if err != nil {
+				if err == io.EOF {
+					n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size))
+				} else {
+					n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
+				}
+				return
+			}
+
+			msg := &ninja_frontend.Status{}
+			err = proto.Unmarshal(buf, msg)
+			if err != nil {
+				n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err))
+				continue
+			}
+
+			msgChan <- msg
+		}
+	}()
+
 	for {
-		size, err := readVarInt(r)
-		if err != nil {
-			if err != io.EOF {
-				n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
-			}
-			return
+		var msg *ninja_frontend.Status
+		var msgOk bool
+		select {
+		case <-n.forceClose:
+			// Close() has been called, but the reader goroutine didn't get EOF after 5 seconds
+			break
+		case msg, msgOk = <-msgChan:
+			// msg is ready or closed
 		}
 
-		buf := make([]byte, size)
-		_, err = io.ReadFull(r, buf)
-		if err != nil {
-			if err == io.EOF {
-				n.status.Print(fmt.Sprintf("Missing message of size %d from ninja\n", size))
-			} else {
-				n.status.Error(fmt.Sprintf("Got error reading from ninja: %s", err))
-			}
-			return
+		if !msgOk {
+			// msgChan is closed
+			break
 		}
-
-		msg := &ninja_frontend.Status{}
-		err = proto.Unmarshal(buf, msg)
-		if err != nil {
-			n.status.Print(fmt.Sprintf("Error reading message from ninja: %v", err))
-			continue
-		}
-
 		// Ignore msg.BuildStarted
 		if msg.TotalEdges != nil {
 			n.status.SetTotalActions(int(msg.TotalEdges.GetTotalEdges()))
diff --git a/xml/xml.go b/xml/xml.go
index 8c0c072..20a26f5 100644
--- a/xml/xml.go
+++ b/xml/xml.go
@@ -146,7 +146,11 @@
 }
 
 func (p *prebuiltEtcXml) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
-	baseAttrs := p.PrebuiltEtc.Bp2buildHelper(ctx)
+	baseAttrs, convertible := p.PrebuiltEtc.Bp2buildHelper(ctx)
+
+	if !convertible {
+		return
+	}
 
 	var schema *string
 	if p.properties.Schema != nil {