Merge "Revert "Only allow setting presigned without preprocessed on targetSdk < 30"" into main
diff --git a/aconfig/java_aconfig_library.go b/aconfig/java_aconfig_library.go
index 53f8bd1..4db0ef7 100644
--- a/aconfig/java_aconfig_library.go
+++ b/aconfig/java_aconfig_library.go
@@ -52,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 {
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index d7fbb62..fb2e0d7 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -228,6 +228,7 @@
 		"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,
@@ -310,6 +311,7 @@
 		"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,
@@ -488,6 +490,55 @@
 	}
 
 	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",
 
@@ -858,6 +909,12 @@
 		"hal_unit_tests",
 
 		"merge_annotation_zips_test",
+
+		// bouncycastle dep
+		"platform-test-annotations",
+
+		// java_resources with multiple resource_dirs
+		"emma",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -881,6 +938,20 @@
 	// 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",
@@ -1546,6 +1617,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
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 94b36e3..e764b18 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -510,12 +510,6 @@
 	}
 
 	module := p.module
-	// In api_bp2build mode, all soong modules that can provide API contributions should be converted
-	// This is irrespective of its presence/absence in bp2build allowlists
-	if ctx.Config().BuildMode == ApiBp2build {
-		_, providesApis := module.(ApiProvider)
-		return providesApis
-	}
 
 	propValue := b.bazelProperties.Bazel_module.Bp2build_available
 	packagePath := moduleDirWithPossibleOverride(ctx, module, p.moduleDir)
@@ -533,13 +527,13 @@
 	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
 	}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 42ba9b4..4b98345 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -1382,10 +1382,7 @@
 			WriteFileRuleVerbatim(ctx, out, "")
 		case "FileWrite", "SourceSymlinkManifest":
 			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
-			// TODO(b/297366783) This is a hack to make files from skylib's diff_test executable.
-			// We need to update bazel to have aquery tell us whether a file is supposed to be
-			// executable or not.
-			if strings.HasSuffix(buildStatement.OutputPaths[0], "-test.sh") {
+			if buildStatement.IsExecutable {
 				WriteExecutableFileRuleVerbatim(ctx, out, buildStatement.FileContents)
 			} else {
 				WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
diff --git a/android/bazel_test.go b/android/bazel_test.go
index 194a6b3..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",
diff --git a/android/config.go b/android/config.go
index 3e7bb14..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
 
@@ -641,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)
@@ -1662,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 {
@@ -1792,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)
 }
@@ -2081,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 682111e..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")
diff --git a/android/module.go b/android/module.go
index 19502ba..516810f 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1371,7 +1371,7 @@
 		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)
 				}
 			}
@@ -1418,10 +1418,42 @@
 	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 productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
diff --git a/android/mutator.go b/android/mutator.go
index 6bcac93..41477b8 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -231,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
diff --git a/android/proto.go b/android/proto.go
index 6887900..fc21d01 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -17,6 +17,7 @@
 import (
 	"path/filepath"
 	"strings"
+	"sync"
 
 	"android/soong/bazel"
 
@@ -281,6 +282,13 @@
 				}
 			}
 
+			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()
@@ -323,7 +331,8 @@
 				Label: l,
 			})
 		}
-		protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, protoIncludeDirs)
+		// Partitioning by packages can create dupes of protoIncludeDirs, so dedupe it first.
+		protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, SortedUniqueStrings(protoIncludeDirs))
 		transitiveProtoLibraries.Append(protoLibrariesInIncludeDir)
 	}
 
@@ -333,15 +342,20 @@
 	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) *map[protoIncludeDirKey]bool {
+func getProtoIncludeDirsBp2build(config Config) *sync.Map {
 	return config.Once(protoIncludeDirsBp2buildKey, func() interface{} {
-		return &map[protoIncludeDirKey]bool{}
-	}).(*map[protoIncludeDirKey]bool)
+		return &sync.Map{}
+	}).(*sync.Map)
 }
 
 // key for dynamically creating proto_library per proto.include_dirs
@@ -371,11 +385,10 @@
 				Label: "//" + pkg + ":" + label,
 			})
 			key := protoIncludeDirKey{dir: dir, subpackgeInDir: pkg}
-			if _, exists := (*dirMap)[key]; exists {
+			if _, exists := dirMap.LoadOrStore(key, true); exists {
 				// A proto_library has already been created for this package relative to this include dir
 				continue
 			}
-			(*dirMap)[key] = true
 			srcs := protoLabelelsPartitionedByPkg[pkg]
 			rel, err := filepath.Rel(dir, pkg)
 			if err != nil {
@@ -389,7 +402,18 @@
 			if rel != "." {
 				attrs.Import_prefix = proptools.StringPtr(rel)
 			}
-			ctx.CreateBazelTargetModule(
+
+			// 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,
@@ -399,6 +423,7 @@
 					Tags: bazel.MakeStringListAttribute([]string{"manual"}),
 				},
 				&attrs,
+				alwaysEnabled,
 			)
 		}
 	}
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 ca9a221..02eff25 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -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"`
@@ -486,6 +481,8 @@
 	ReleaseAconfigFlagDefaultPermission string `json:",omitempty"`
 
 	KeepVndk *bool `json:",omitempty"`
+
+	CheckVendorSeappViolations *bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index 52a5e20..1e65b0f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -2008,6 +2008,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
 		}
 	}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1717f3e..9475f5d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7977,7 +7977,8 @@
 		apex {
 			name: "myapex",
 			key: "myapex.key",
-			jni_libs: ["mylib", "libfoo.rust"],
+			binaries: ["mybin"],
+			jni_libs: ["mylib", "mylib3", "libfoo.rust"],
 			updatable: false,
 		}
 
@@ -8004,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",
@@ -8027,10 +8046,12 @@
 
 	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")
+	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
diff --git a/bazel/aquery.go b/bazel/aquery.go
index d77d59a..76cd972 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -123,6 +123,7 @@
 	// Unlike most properties in BuildStatement, these paths must be relative to the root of
 	// the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
 	ImplicitDeps []string
+	IsExecutable bool
 }
 
 // A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -560,6 +561,7 @@
 		Mnemonic:          actionEntry.Mnemonic,
 		InputDepsetHashes: depsetHashes,
 		FileContents:      actionEntry.FileContents,
+		IsExecutable:      actionEntry.IsExecutable,
 	}, nil
 }
 
diff --git a/bazel/configurability.go b/bazel/configurability.go
index aa58fdc..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"
@@ -170,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",
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index c104833..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",
@@ -61,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",
@@ -82,6 +82,10 @@
         "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",
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 09d9dc1..a24378c 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -37,19 +37,19 @@
 		},
 		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"),
 		}})
 }
 
@@ -87,10 +84,11 @@
 		},
 		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."),
@@ -121,6 +119,7 @@
         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 8ed94b4..f2ee322 100644
--- a/bp2build/android_app_conversion_test.go
+++ b/bp2build/android_app_conversion_test.go
@@ -44,9 +44,14 @@
 		},
 		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{
@@ -75,17 +80,25 @@
 		},
 		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"],
-        asset_dirs: ["assets_"],
+	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{
@@ -103,6 +116,14 @@
 				"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)"`,
 			}),
 		}})
 }
@@ -120,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{
@@ -142,6 +166,7 @@
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `["res/res.png"]`,
 				"sdk_version":    `"current"`,
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -154,8 +179,12 @@
 		Filesystem:                 map[string]string{},
 		Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "foocert") + `
 android_app {
-        name: "TestApp",
-        certificate: ":foocert",
+	name: "TestApp",
+	certificate: ":foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -163,6 +192,8 @@
 				"certificate":    `":foocert"`,
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
+				"sdk_version":    `"current"`, // use as default
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -177,8 +208,12 @@
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        certificate: "foocert",
+	name: "TestApp",
+	certificate: "foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -186,6 +221,8 @@
 				"certificate":    `"foocert"`,
 				"manifest":       `"AndroidManifest.xml"`,
 				"resource_files": `[]`,
+				"sdk_version":    `"current"`, // use as default
+				"optimize":       `False`,
 			}),
 		}})
 }
@@ -200,8 +237,12 @@
 		},
 		Blueprint: `
 android_app {
-        name: "TestApp",
-        certificate: "foocert",
+	name: "TestApp",
+	certificate: "foocert",
+	sdk_version: "current",
+	optimize: {
+		enabled: false,
+	},
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -209,6 +250,8 @@
 				"certificate_name": `"foocert"`,
 				"manifest":         `"AndroidManifest.xml"`,
 				"resource_files":   `[]`,
+				"sdk_version":      `"current"`, // use as default
+				"optimize":         `False`,
 			}),
 		}})
 }
@@ -219,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`,
 			}),
 		}})
 }
@@ -247,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",
@@ -270,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`,
 			}),
 		}})
 }
@@ -287,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`,
 			}),
 		}})
 }
@@ -326,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{
@@ -347,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`,
 			}),
 		}})
 }
@@ -362,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{
@@ -381,6 +440,7 @@
         "targetSdkVersion": "29",
     }`,
 				"sdk_version": `"current"`,
+				"optimize":    `False`,
 			}),
 		}})
 }
@@ -391,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{
@@ -406,6 +469,7 @@
         "targetSdkVersion": "30",
     }`,
 				"sdk_version": `"30"`,
+				"optimize":    `False`,
 			}),
 		}})
 }
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index e8c2ef7..7717993 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -1,9 +1,6 @@
 package bp2build
 
 import (
-	"android/soong/android"
-	"android/soong/android/soongconfig"
-	"android/soong/starlark_import"
 	"encoding/json"
 	"fmt"
 	"os"
@@ -11,6 +8,10 @@
 	"reflect"
 	"strings"
 
+	"android/soong/android"
+	"android/soong/android/soongconfig"
+	"android/soong/starlark_import"
+
 	"github.com/google/blueprint/proptools"
 	"go.starlark.net/starlark"
 )
@@ -258,12 +259,16 @@
 		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)))
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index cd1bc7f..9060363 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -175,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
@@ -196,8 +193,6 @@
 		return "Bp2Build"
 	case QueryView:
 		return "QueryView"
-	case ApiBp2build:
-		return "ApiBp2build"
 	default:
 		return fmt.Sprintf("%d", mode)
 	}
@@ -774,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 8ee0439..3887c5d 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1879,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 {
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 6501217..246f169 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -2839,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",
@@ -5120,7 +4921,7 @@
 	// bar dir
 	tc.Dir = "bar"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["bar.proto"]`,
 			"strip_import_prefix": `""`,
 			"tags":                `["manual"]`,
@@ -5131,7 +4932,7 @@
 	// bar/baz dir
 	tc.Dir = "bar/baz"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["//bar/baz:baz.proto"]`,
 			"strip_import_prefix": `""`,
 			"import_prefix":       `"baz"`,
@@ -5141,6 +4942,52 @@
 	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",
@@ -5187,7 +5034,7 @@
 	// foo/foo_subdir
 	tc.Dir = "foo/foo_subdir"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["foo_subdir.proto"]`,
 			"strip_import_prefix": `""`,
 			"tags":                `["manual"]`,
@@ -5195,3 +5042,96 @@
 	}
 	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..a592ca9 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) {
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 76bbb57..9639ab9 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -139,6 +139,13 @@
         "host_without_device",
         "device",
     ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -166,6 +173,13 @@
         "host_without_device",
         "device",
     ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -197,6 +211,13 @@
         "host_without_device",
         "device",
     ]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -228,6 +249,13 @@
         ":libgtest",
     ]`,
 				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -260,6 +288,13 @@
         ":libgtest",
     ]`,
 				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -297,6 +332,13 @@
 				"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": [],
+    })`,
 			},
 			},
 		},
@@ -324,6 +366,13 @@
         ":libgtest_main",
     ]`,
 				"runs_on": `["device"]`,
+				"features": `select({
+        "//build/bazel/platforms/os_arch:android_arm64": [
+            "memtag_heap",
+            "diag_memtag_heap",
+        ],
+        "//conditions:default": [],
+    })`,
 			},
 			},
 		},
@@ -350,6 +399,13 @@
 				"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": [],
+    })`,
 			},
 			},
 		},
@@ -381,6 +437,13 @@
 				"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{
@@ -388,6 +451,166 @@
 				"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 7791419..da4b5cf 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -48,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 {
@@ -141,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 cbffaa0..89dd38e 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -134,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/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..7429ae6 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,67 @@
         "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": "",
+			"res1/b.res": "",
 		},
 		Blueprint: `java_library {
-    name: "java-lib-1",
+	name: "java-lib-1",
 	java_resource_dirs: ["res", "res1"],
+	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 +501,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 +528,7 @@
         "a.java",
         "b.java",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 		}})
@@ -450,12 +541,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 +557,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 +590,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 +619,7 @@
         "b.java",
         ":random_other_files",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "example_lib"),
 			MakeBazelTargetNoRestrictions("filegroup", "random_other_files", AttrNameToString{
@@ -547,24 +642,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"),
 		},
@@ -581,16 +678,17 @@
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
 		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			neon: {
-				srcs: ["arm_neon.java"],
-			},
-		},
-	},
+  name: "TestLib",
+  manifest: "manifest/AndroidManifest.xml",
+  srcs: ["lib.java"],
+  sdk_version: "current",
+  arch: {
+    arm: {
+      neon: {
+        srcs: ["arm_neon.java"],
+      },
+    },
+  },
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -604,6 +702,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -617,19 +716,20 @@
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
 		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		x86: {
-			ssse3: {
-				srcs: ["ssse3.java"],
-			},
-			sse4_1: {
-				srcs: ["sse4_1.java"],
-			},
-		},
-	},
+  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 +748,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`,
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -661,17 +762,18 @@
 		ModuleTypeUnderTestFactory: java.AndroidLibraryFactory,
 		Blueprint: simpleModuleDoNotConvertBp2build("android_library", "static_lib_dep") + `
 android_library {
-	name: "TestLib",
-	manifest: "manifest/AndroidManifest.xml",
-	srcs: ["lib.java"],
-	arch: {
-		arm: {
-			srcs: ["arm_non_neon.java"],
-			neon: {
-				exclude_srcs: ["arm_non_neon.java"],
-			},
-		},
-	},
+  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 +788,7 @@
     })`,
 					"manifest":       `"manifest/AndroidManifest.xml"`,
 					"resource_files": `[]`,
+					"sdk_version":    `"current"`, // use as default
 				}),
 			MakeNeverlinkDuplicateTarget("android_library", "TestLib"),
 		}})
@@ -698,6 +801,7 @@
     name: "java-lib-1",
     srcs: ["a.java", "b.java", "c.kt"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -707,6 +811,7 @@
         "b.java",
         "c.kt",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -721,6 +826,7 @@
     srcs: [ "a.kt"],
     kotlincflags: ["-flag1", "-flag2"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -730,6 +836,7 @@
         "-flag1",
         "-flag2",
     ]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -744,6 +851,7 @@
     srcs: ["a.java", "b.java"],
     common_srcs: ["c.kt"],
     bazel_module: { bp2build_available: true },
+    sdk_version: "current",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -753,6 +861,7 @@
         "b.java",
     ]`,
 				"common_srcs": `["c.kt"]`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("kt_jvm_library", "java-lib-1"),
 		},
@@ -766,6 +875,7 @@
     name: "java-lib-1",
     srcs: ["a.java"],
     libs: ["java-lib-2"],
+    sdk_version: "current",
     target: {
         android: {
             libs: ["java-lib-3"],
@@ -775,16 +885,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 +914,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 +927,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java", "b.java"],
+    sdk_version: "current",
     target: {
         android: {
             exclude_srcs: ["a.java"],
@@ -833,6 +942,7 @@
         "//build/bazel/platforms/os:android": [],
         "//conditions:default": ["a.java"],
     })`,
+				"sdk_version": `"current"`,
 			}),
 			MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
 		},
@@ -850,6 +960,7 @@
 		Blueprint: `java_library {
     name: "java-lib-1",
     srcs: ["a.java"],
+    sdk_version: "current",
     java_resources: [":filegroup1"],
     bazel_module: { bp2build_available: true },
 }
@@ -866,6 +977,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 +990,59 @@
 		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)
+	})
+}
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/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/testing.go b/bp2build/testing.go
index 18ae82d..997df64 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
@@ -688,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/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/bp2build.go b/cc/bp2build.go
index 7f78e28..83553c8 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -851,7 +851,7 @@
 	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{})
@@ -1936,6 +1936,8 @@
 	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 {
@@ -1960,9 +1962,18 @@
 					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)
 		}
 	})
+	sanitizerFeatures.Append(memtagFeatures)
+
 	return sanitizerValues{
 		features:                 sanitizerFeatures,
 		copts:                    sanitizerCopts,
@@ -1970,6 +1981,26 @@
 	}
 }
 
+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 {
 	lto_feature_name := "android_thin_lto"
 	ltoBoolFeatures := bazel.BoolAttribute{}
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/global.go b/cc/config/global.go
index 23a05be..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",
@@ -140,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",
 	}
@@ -167,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...)
@@ -251,9 +255,6 @@
 	noOverrideExternalGlobalCflags = []string{
 		// http://b/191699019
 		"-Wno-format-insufficient-args",
-		// http://b/296422292
-		// Usually signals a mistake and should be a hard error.
-		"-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.
@@ -320,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/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 820c1f0..df9ca0a 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -162,7 +162,7 @@
 }
 
 func GlobalThinLTO(ctx android.BaseModuleContext) bool {
-	return ctx.Config().IsEnvTrue("GLOBAL_THINLTO")
+	return !ctx.Config().IsEnvFalse("GLOBAL_THINLTO")
 }
 
 // Propagate lto requirements down from binaries
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 8eea7db..0abdafc 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -553,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 {
@@ -1189,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
 			}
 		})
@@ -1243,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{""}
@@ -1280,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
 			}
 		}
@@ -1396,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())
@@ -1420,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)
 }
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/test.go b/cc/test.go
index adc80c2..ae62128 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -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"})
@@ -720,6 +722,21 @@
 		}
 	}
 
+	// 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")
+		}
+	}
+
+	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)
@@ -745,7 +762,7 @@
 				p.Auto_gen_config,
 				p.Test_options.Test_suite_tag,
 				p.Test_config_template,
-				getTradefedConfigOptions(ctx, p, gtestIsolated),
+				getTradefedConfigOptions(ctx, p, gtestIsolated, true),
 				&testInstallBase,
 			)
 			testBinaryAttrs.TestConfigAttributes = testConfigAttributes
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 20e366e..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")
@@ -169,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")
@@ -551,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()
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_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/genrule/genrule.go b/genrule/genrule.go
index 8e3f278..d1c2f13 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -912,7 +912,7 @@
 	Out []string
 }
 
-type bazelGenruleAttributes struct {
+type BazelGenruleAttributes struct {
 	Srcs  bazel.LabelListAttribute
 	Outs  []string
 	Tools bazel.LabelListAttribute
@@ -1036,7 +1036,7 @@
 				break
 			}
 		}
-		attrs := &bazelGenruleAttributes{
+		attrs := &BazelGenruleAttributes{
 			Srcs:  srcs,
 			Outs:  outs,
 			Cmd:   cmdProp,
diff --git a/java/app.go b/java/app.go
index 7cf86c0..d71cd77 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"
 )
 
@@ -1059,6 +1060,7 @@
 
 	module.Module.dexProperties.Optimize.EnabledByDefault = true
 	module.Module.dexProperties.Optimize.Shrink = proptools.BoolPtr(true)
+	module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false)
 
 	module.Module.properties.Instrument = true
 	module.Module.properties.Supports_static_instrumentation = true
@@ -1613,6 +1615,8 @@
 	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.
@@ -1664,6 +1668,41 @@
 		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))
+		}
+
+	}
+
 	props := bazel.BazelTargetModuleProperties{
 		Rule_class:        "android_binary",
 		Bzl_load_location: "//build/bazel/rules/android:android_binary.bzl",
diff --git a/java/dex.go b/java/dex.go
index df501bf..21937e1 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -45,8 +45,8 @@
 		// Whether to continue building even if warnings are emitted.  Defaults to true.
 		Ignore_warnings *bool
 
-		// If true, runs R8 in Proguard compatibility mode (default).
-		// Otherwise, runs R8 in full mode.
+		// If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode.
+		// Defaults to false for apps, true for libraries and tests.
 		Proguard_compatibility *bool
 
 		// If true, optimize for size by removing unused code.  Defaults to true for apps,
@@ -217,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)
@@ -226,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
 }
 
diff --git a/java/generated_java_library.go b/java/generated_java_library.go
index 1cab6ac..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)
 }
 
diff --git a/java/java.go b/java/java.go
index fe7f88f..521aef3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -21,6 +21,7 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 
 	"android/soong/bazel"
@@ -1734,7 +1735,6 @@
 
 	cmd.Flag("--color").
 		Flag("--quiet").
-		Flag("--format=v2").
 		Flag("--include-annotations").
 		// The flag makes nullability issues as warnings rather than errors by replacing
 		// @Nullable/@NonNull in the listed packages APIs with @RecentlyNullable/@RecentlyNonNull,
@@ -1746,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
 }
 
@@ -1915,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
@@ -2756,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
@@ -2792,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 {
+				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),
 	}
 }
 
@@ -2867,6 +2903,11 @@
 	var deps bazel.LabelListAttribute
 	var staticDeps bazel.LabelListAttribute
 
+	if proptools.String(m.deviceProperties.Sdk_version) == "" && m.DeviceSupported() {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "sdk_version unset")
+		return &javaCommonAttributes{}, &bp2BuildJavaInfo{}, false
+	}
+
 	archVariantProps := m.GetArchVariantProperties(ctx, &CommonProperties{})
 	for axis, configToProps := range archVariantProps {
 		for config, _props := range configToProps {
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/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/python.go b/python/python.go
index e6bdeee..7d77ca7 100644
--- a/python/python.go
+++ b/python/python.go
@@ -197,6 +197,14 @@
 	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
 }
@@ -454,8 +462,7 @@
 
 	// generate the zipfile of all source and data files
 	p.srcsZip = p.createSrcsZip(ctx, pkgPath)
-	// TODO(b/278602456): precompilation temporarily disabled for python3.11 upgrade
-	p.precompiledSrcsZip = p.srcsZip //p.precompileSrcs(ctx)
+	p.precompiledSrcsZip = p.precompileSrcs(ctx)
 }
 
 func isValidPythonPath(path string) error {
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/config/global.go b/rust/config/global.go
index ca2c9af..4bd495d 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -54,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",
 	}
diff --git a/rust/fuzz.go b/rust/fuzz.go
index 235f517..4c04ce8 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -60,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/library.go b/rust/library.go
index 419fcfc..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,
@@ -793,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/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 a14ebea..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 (
@@ -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 689ff38..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"
 
@@ -169,6 +171,8 @@
 	apexSdkVersion android.ApiLevel
 
 	transitiveAndroidMkSharedLibs *android.DepSet[string]
+
+	android.BazelModuleBase
 }
 
 func (mod *Module) Header() bool {
@@ -1841,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/sanitize.go b/rust/sanitize.go
index cc19e6e..2f5afd7 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -208,6 +208,11 @@
 		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 non-windows targets
 	if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) {
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/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 5459904..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) {
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/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 090114b..8a64a56 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -407,38 +407,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/sbom_test.sh b/tests/sbom_test.sh
index 9801a8e..9de9b97 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -85,46 +85,7 @@
   lz4=$out_dir/host/linux-x86/bin/lz4
 
   declare -A diff_excludes
-  diff_excludes[vendor]="\
-    -I /vendor/lib64/libkeystore2_crypto.so \
-    -I /vendor/lib64/libvsock_utils.so"
-  diff_excludes[system]="\
-    -I /system/bin/assemble_cvd \
-    -I /system/bin/console_forwarder \
-    -I /system/bin/kernel_log_monitor \
-    -I /system/bin/logcat_receiver \
-    -I /system/bin/mkenvimage_slim \
-    -I /system/bin/run_cvd \
-    -I /system/bin/simg2img \
-    -I /system/bin/log_tee \
-    -I /system/lib64/android.hardware.confirmationui@1.0.so \
-    -I /system/lib64/android.hardware.confirmationui-V1-ndk.so \
-    -I /system/lib64/android.hardware.keymaster@4.1.so \
-    -I /system/lib64/android.hardware.security.rkp-V3-ndk.so \
-    -I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
-    -I /system/lib64/android.security.compat-ndk.so \
-    -I /system/lib64/libcuttlefish_allocd_utils.so \
-    -I /system/lib64/libcuttlefish_device_config_proto.so \
-    -I /system/lib64/libcuttlefish_device_config.so \
-    -I /system/lib64/libcuttlefish_fs.so \
-    -I /system/lib64/libcuttlefish_kernel_log_monitor_utils.so \
-    -I /system/lib64/libcuttlefish_utils.so \
-    -I /system/lib64/libfruit.so \
-    -I /system/lib64/libgflags.so \
-    -I /system/lib64/libkeymaster4_1support.so \
-    -I /system/lib64/libkeymaster4support.so \
-    -I /system/lib64/libkeymint.so \
-    -I /system/lib64/libkeystore2_aaid.so \
-    -I /system/lib64/libkeystore2_apc_compat.so \
-    -I /system/lib64/libkeystore2_crypto.so \
-    -I /system/lib64/libkeystore-attestation-application-id.so \
-    -I /system/lib64/libkm_compat_service.so \
-    -I /system/lib64/libkm_compat.so \
-    -I /system/lib64/vndk-29 \
-    -I /system/lib64/vndk-sp-29 \
-    -I /system/lib/vndk-29 \
-    -I /system/lib/vndk-sp-29 \
-    -I /system/usr/icu"
+  diff_excludes[system]="-I /system/bin/hwservicemanager"
 
   # 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.
diff --git a/ui/build/config.go b/ui/build/config.go
index 5d1505a..084d28d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -70,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.
@@ -869,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" {
@@ -970,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
 	}
@@ -1068,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")
 }
@@ -1113,10 +1106,6 @@
 	return c.bp2build
 }
 
-func (c *configImpl) ApiBp2build() bool {
-	return c.apiBp2build
-}
-
 func (c *configImpl) Queryview() bool {
 	return c.queryview
 }
@@ -1308,7 +1297,7 @@
 
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
-	if c.Bp2Build() || c.Queryview() || c.ApiBp2build() || c.JsonModuleGraph() {
+	if c.Bp2Build() || c.Queryview() || c.JsonModuleGraph() {
 		return false
 	}
 
diff --git a/ui/build/soong.go b/ui/build/soong.go
index b8543d9..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
@@ -264,7 +263,6 @@
 		config.NamedGlobFile(bp2buildFilesTag),
 		config.NamedGlobFile(jsonModuleGraphTag),
 		config.NamedGlobFile(queryviewTag),
-		config.NamedGlobFile(apiBp2buildTag),
 		config.NamedGlobFile(soongDocsTag),
 	}
 }
@@ -305,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{
 		{
@@ -355,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,
@@ -533,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))
 		}
@@ -608,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()))