Merge "riscv64: assume fast unaligned access." into main
diff --git a/README.md b/README.md
index 22daa95..5e9e04a 100644
--- a/README.md
+++ b/README.md
@@ -648,8 +648,8 @@
 SOONG_DELVE=2345 SOONG_DELVE_STEPS='build,modulegraph' m
 ```
 results in only `build` (main build step) and `modulegraph` being run in the debugger.
-The allowed step names are `api_bp2build`, `bp2build_files`, `bp2build_workspace`,
-`build`, `modulegraph`, `queryview`, `soong_docs`.
+The allowed step names are `bp2build_files`, `bp2build_workspace`, `build`,
+`modulegraph`, `queryview`, `soong_docs`.
 
 Note setting or unsetting `SOONG_DELVE` causes a recompilation of `soong_build`. This
 is because in order to debug the binary, it needs to be built with debug
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 6014deb..bcb98f7 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -324,30 +324,31 @@
 
 		"libnativehelper": Bp2BuildDefaultTrueRecursively,
 
-		"packages/apps/DevCamera":                            Bp2BuildDefaultTrue,
-		"packages/apps/HTMLViewer":                           Bp2BuildDefaultTrue,
-		"packages/apps/Protips":                              Bp2BuildDefaultTrue,
-		"packages/apps/SafetyRegulatoryInfo":                 Bp2BuildDefaultTrue,
-		"packages/apps/WallpaperPicker":                      Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/driver/cache":       Bp2BuildDefaultTrueRecursively,
-		"packages/modules/StatsD/lib/libstatssocket":         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb":                               Bp2BuildDefaultTrue,
-		"packages/modules/adb/apex":                          Bp2BuildDefaultTrue,
-		"packages/modules/adb/fastdeploy":                    Bp2BuildDefaultTrue,
-		"packages/modules/adb/crypto":                        Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/libs":                          Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_auth":                  Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/pairing_connection":            Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/proto":                         Bp2BuildDefaultTrueRecursively,
-		"packages/modules/adb/tls":                           Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Connectivity/staticlibs/native":    Bp2BuildDefaultTrueRecursively,
-		"packages/modules/Gki/libkver":                       Bp2BuildDefaultTrue,
-		"packages/modules/NetworkStack/common/captiveportal": Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex":               Bp2BuildDefaultTrue,
-		"packages/modules/NeuralNetworks/apex/testing":       Bp2BuildDefaultTrue,
-		"packages/providers/MediaProvider/tools/dialogs":     Bp2BuildDefaultFalse, // TODO(b/242834374)
-		"packages/screensavers/Basic":                        Bp2BuildDefaultTrue,
-		"packages/services/Car/tests/SampleRearViewCamera":   Bp2BuildDefaultFalse, // TODO(b/242834321)
+		"packages/apps/DevCamera":                                    Bp2BuildDefaultTrue,
+		"packages/apps/HTMLViewer":                                   Bp2BuildDefaultTrue,
+		"packages/apps/Protips":                                      Bp2BuildDefaultTrue,
+		"packages/apps/SafetyRegulatoryInfo":                         Bp2BuildDefaultTrue,
+		"packages/apps/WallpaperPicker":                              Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/driver/cache":               Bp2BuildDefaultTrueRecursively,
+		"packages/modules/StatsD/lib/libstatssocket":                 Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb":                                       Bp2BuildDefaultTrue,
+		"packages/modules/adb/apex":                                  Bp2BuildDefaultTrue,
+		"packages/modules/adb/fastdeploy":                            Bp2BuildDefaultTrue,
+		"packages/modules/adb/crypto":                                Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/libs":                                  Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_auth":                          Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/pairing_connection":                    Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/proto":                                 Bp2BuildDefaultTrueRecursively,
+		"packages/modules/adb/tls":                                   Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/native":            Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Connectivity/staticlibs/netd/libnetdutils": Bp2BuildDefaultTrueRecursively,
+		"packages/modules/Gki/libkver":                               Bp2BuildDefaultTrue,
+		"packages/modules/NetworkStack/common/captiveportal":         Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex":                       Bp2BuildDefaultTrue,
+		"packages/modules/NeuralNetworks/apex/testing":               Bp2BuildDefaultTrue,
+		"packages/providers/MediaProvider/tools/dialogs":             Bp2BuildDefaultFalse, // TODO(b/242834374)
+		"packages/screensavers/Basic":                                Bp2BuildDefaultTrue,
+		"packages/services/Car/tests/SampleRearViewCamera":           Bp2BuildDefaultFalse, // TODO(b/242834321)
 
 		"platform_testing/libraries/annotations":              Bp2BuildDefaultTrueRecursively,
 		"platform_testing/libraries/flag-helpers/libflagtest": Bp2BuildDefaultTrueRecursively,
@@ -524,7 +525,6 @@
 	}
 
 	Bp2buildModuleAlwaysConvertList = []string{
-		"AconfigJavaHostTest",
 		// aconfig
 		"libonce_cell",
 		"libanyhow",
@@ -1020,6 +1020,7 @@
 		"ndk_headers",
 		"ndk_library",
 		"sysprop_library",
+		"versioned_ndk_headers",
 		"xsd_config",
 		// go/keep-sorted end
 	}
diff --git a/android/api_domain.go b/android/api_domain.go
index 0603c70..0a66c3d 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -14,20 +14,6 @@
 
 package android
 
-import (
-	"github.com/google/blueprint"
-
-	"android/soong/bazel"
-)
-
-func init() {
-	RegisterApiDomainBuildComponents(InitRegistrationContext)
-}
-
-func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
-	ctx.RegisterModuleType("api_domain", ApiDomainFactory)
-}
-
 type ApiSurface int
 
 // TODO(b/246656800): Reconcile with android.SdkKind
@@ -50,60 +36,3 @@
 		return "invalid"
 	}
 }
-
-type apiDomain struct {
-	ModuleBase
-	BazelModuleBase
-
-	properties apiDomainProperties
-}
-
-type apiDomainProperties struct {
-	// cc library contributions (.h files/.map.txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `CcApiContributionInfo` provider
-	Cc_api_contributions []string
-
-	// java library contributions (as .txt) of this API domain
-	// This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
-	// will provide a `JavaApiContributionInfo` provider
-	Java_api_contributions []string
-}
-
-func ApiDomainFactory() Module {
-	m := &apiDomain{}
-	m.AddProperties(&m.properties)
-	InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
-	return m
-}
-
-// Do not create any dependency edges in Soong for now to skip visibility checks for some systemapi libraries.
-// Currently, all api_domain modules reside in build/orchestrator/apis/Android.bp
-// However, cc libraries like libsigchain (com.android.art) restrict their visibility to art/*
-// When the api_domain module types are collocated with their contributions, this dependency edge can be restored
-func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
-// API domain does not have any builld actions yet
-func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
-}
-
-const (
-	apiContributionSuffix = ".contribution"
-)
-
-// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution)  of contribution modules (e.g. ndk_library)
-// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
-func ApiContributionTargetName(moduleName string) string {
-	return moduleName + apiContributionSuffix
-}
-
-// For each contributing cc_library, format the name to its corresponding contribution bazel target in the bp2build workspace
-func contributionBazelAttributes(ctx TopDownMutatorContext, contributions []string) bazel.LabelListAttribute {
-	addSuffix := func(ctx BazelConversionPathContext, module blueprint.Module) string {
-		baseLabel := BazelModuleLabel(ctx, module)
-		return ApiContributionTargetName(baseLabel)
-	}
-	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
-	return bazel.MakeLabelListAttribute(bazelLabels)
-}
diff --git a/android/bazel.go b/android/bazel.go
index 5df12f0..e307b18 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -625,7 +625,18 @@
 	ctx.BottomUp("bp2build_conversion", bp2buildConversionMutator).Parallel()
 }
 
+func registerBp2buildDepsMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("bp2build_deps", bp2buildDepsMutator).Parallel()
+}
+
 func bp2buildConversionMutator(ctx BottomUpMutatorContext) {
+	// If an existing BUILD file in the module directory has a target defined
+	// with this same name as this module, assume that this is an existing
+	// definition for this target.
+	if ctx.Config().HasBazelBuildTargetInSource(ctx.ModuleDir(), ctx.ModuleName()) {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, ctx.ModuleName())
+		return
+	}
 	bModule, ok := ctx.Module().(Bazelable)
 	if !ok {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
@@ -659,6 +670,10 @@
 		panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName()))
 	}
 
+	// If an existing BUILD file in the module directory has a target defined
+	// with the same name as any target generated by this module, assume that this
+	// is an existing definition for this target. (These generated target names
+	// may be different than the module name, as checked at the beginning of this function!)
 	for _, targetInfo := range ctx.Module().base().Bp2buildTargets() {
 		if ctx.Config().HasBazelBuildTargetInSource(targetInfo.TargetPackage(), targetInfo.TargetName()) {
 			// Defer to the BUILD target. Generating an additional target would
@@ -669,6 +684,27 @@
 	}
 }
 
+// TODO: b/285631638 - Add this as a new mutator to the bp2build conversion mutators.
+// Currently, this only exists to prepare test coverage for the launch of this feature.
+func bp2buildDepsMutator(ctx BottomUpMutatorContext) {
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
+	if len(ctx.Module().GetMissingBp2buildDeps()) > 0 {
+		exampleDep := ctx.Module().GetMissingBp2buildDeps()[0]
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, exampleDep)
+	}
+
+	ctx.VisitDirectDeps(func(dep Module) {
+		if dep.base().GetUnconvertedReason() != nil &&
+			dep.base().GetUnconvertedReason().ReasonType != int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) &&
+			ctx.OtherModuleDependencyTag(dep) == Bp2buildDepTag {
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNCONVERTED_DEP, dep.Name())
+		}
+	})
+}
+
 // GetMainClassInManifest scans the manifest file specified in filepath and returns
 // the value of attribute Main-Class in the manifest file if it exists, or returns error.
 // WARNING: this is for bp2build converters of java_* modules only.
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 09580a7..a554775 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -102,8 +102,8 @@
 // BazelLabelForModuleDeps expects a list of reference to other modules, ("<module>"
 // or ":<module>") and returns a Bazel-compatible label which corresponds to dependencies on the
 // module within the given ctx.
-func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
-	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel)
+func BazelLabelForModuleDeps(ctx Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return BazelLabelForModuleDepsWithFn(ctx, modules, BazelModuleLabel, true)
 }
 
 // BazelLabelForModuleWholeDepsExcludes expects two lists: modules (containing modules to include in
@@ -112,15 +112,16 @@
 // list which corresponds to dependencies on the module within the given ctx, and the excluded
 // dependencies.  Prebuilt dependencies will be appended with _alwayslink so they can be handled as
 // whole static libraries.
-func BazelLabelForModuleDepsExcludes(ctx BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func BazelLabelForModuleDepsExcludes(ctx Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, BazelModuleLabel)
 }
 
 // BazelLabelForModuleDepsWithFn expects a list of reference to other modules, ("<module>"
 // or ":<module>") and applies moduleToLabelFn to determine and return a Bazel-compatible label
 // which corresponds to dependencies on the module within the given ctx.
-func BazelLabelForModuleDepsWithFn(ctx BazelConversionPathContext, modules []string,
-	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
+func BazelLabelForModuleDepsWithFn(ctx Bp2buildMutatorContext, modules []string,
+	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDeps bool) bazel.LabelList {
 	var labels bazel.LabelList
 	// In some cases, a nil string list is different than an explicitly empty list.
 	if len(modules) == 0 && modules != nil {
@@ -134,7 +135,7 @@
 			module = ":" + module
 		}
 		if m, t := SrcIsModuleWithTag(module); m != "" {
-			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn)
+			l := getOtherModuleLabel(ctx, m, t, moduleToLabelFn, markAsDeps)
 			if l != nil {
 				l.OriginalModuleName = bpText
 				labels.Includes = append(labels.Includes, *l)
@@ -151,27 +152,27 @@
 // to other modules, ("<module>" or ":<module>"). It applies moduleToLabelFn to determine and return a
 // Bazel-compatible label list which corresponds to dependencies on the module within the given ctx, and
 // the excluded dependencies.
-func BazelLabelForModuleDepsExcludesWithFn(ctx BazelConversionPathContext, modules, excludes []string,
+func BazelLabelForModuleDepsExcludesWithFn(ctx Bp2buildMutatorContext, modules, excludes []string,
 	moduleToLabelFn func(BazelConversionPathContext, blueprint.Module) string) bazel.LabelList {
-	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn)
+	moduleLabels := BazelLabelForModuleDepsWithFn(ctx, RemoveListFromList(modules, excludes), moduleToLabelFn, true)
 	if len(excludes) == 0 {
 		return moduleLabels
 	}
-	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn)
+	excludeLabels := BazelLabelForModuleDepsWithFn(ctx, excludes, moduleToLabelFn, false)
 	return bazel.LabelList{
 		Includes: moduleLabels.Includes,
 		Excludes: excludeLabels.Includes,
 	}
 }
 
-func BazelLabelForModuleSrcSingle(ctx BazelConversionPathContext, path string) bazel.Label {
+func BazelLabelForModuleSrcSingle(ctx Bp2buildMutatorContext, path string) bazel.Label {
 	if srcs := BazelLabelForModuleSrcExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
 		return srcs[0]
 	}
 	return bazel.Label{}
 }
 
-func BazelLabelForModuleDepSingle(ctx BazelConversionPathContext, path string) bazel.Label {
+func BazelLabelForModuleDepSingle(ctx Bp2buildMutatorContext, path string) bazel.Label {
 	if srcs := BazelLabelForModuleDepsExcludes(ctx, []string{path}, []string(nil)).Includes; len(srcs) > 0 {
 		return srcs[0]
 	}
@@ -184,7 +185,7 @@
 // relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
+func BazelLabelForModuleSrc(ctx Bp2buildMutatorContext, paths []string) bazel.LabelList {
 	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
 }
 
@@ -194,13 +195,13 @@
 // (absolute if in a different package or relative if within the same package).
 // Properties must have been annotated with struct tag `android:"path"` so that dependencies modules
 // will have already been handled by the pathdeps mutator.
-func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
-	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
+func BazelLabelForModuleSrcExcludes(ctx Bp2buildMutatorContext, paths, excludes []string) bazel.LabelList {
+	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil), false)
 	excluded := make([]string, 0, len(excludeLabels.Includes))
 	for _, e := range excludeLabels.Includes {
 		excluded = append(excluded, e.Label)
 	}
-	labels := expandSrcsForBazel(ctx, paths, excluded)
+	labels := expandSrcsForBazel(ctx, paths, excluded, true)
 	labels.Excludes = excludeLabels.Includes
 	labels = TransformSubpackagePaths(ctx.Config(), ctx.ModuleDir(), labels)
 	return labels
@@ -361,6 +362,12 @@
 	return newPaths
 }
 
+var Bp2buildDepTag bp2buildDepTag
+
+type bp2buildDepTag struct {
+	blueprint.BaseDependencyTag
+}
+
 // expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local source
 // directory and Bazel target labels, excluding those included in the excludes argument (which
 // should already be expanded to resolve references to Soong-modules). Valid elements of paths
@@ -383,7 +390,7 @@
 // Properties passed as the paths or excludes argument must have been annotated with struct tag
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // pathdeps mutator.
-func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+func expandSrcsForBazel(ctx Bp2buildMutatorContext, paths, expandedExcludes []string, markAsDeps bool) bazel.LabelList {
 	if paths == nil {
 		return bazel.LabelList{}
 	}
@@ -400,7 +407,7 @@
 
 	for _, p := range paths {
 		if m, tag := SrcIsModuleWithTag(p); m != "" {
-			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel)
+			l := getOtherModuleLabel(ctx, m, tag, BazelModuleLabel, markAsDeps)
 			if l != nil && !InList(l.Label, expandedExcludes) {
 				if strings.HasPrefix(m, "//") {
 					// this is a module in a soong namespace
@@ -432,8 +439,9 @@
 // getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
 // module. The label will be relative to the current directory if appropriate. The dependency must
 // already be resolved by either deps mutator or path deps mutator.
-func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string,
-	labelFromModule func(BazelConversionPathContext, blueprint.Module) string) *bazel.Label {
+func getOtherModuleLabel(ctx Bp2buildMutatorContext, dep, tag string,
+	labelFromModule func(BazelConversionPathContext, blueprint.Module) string,
+	markAsDep bool) *bazel.Label {
 	m, _ := ctx.ModuleFromName(dep)
 	// The module was not found in an Android.bp file, this is often due to:
 	//		* a limited manifest
@@ -444,6 +452,13 @@
 			Label: ":" + dep + "__BP2BUILD__MISSING__DEP",
 		}
 	}
+	if markAsDep {
+		// Don't count dependencies of "libc". This is a hack to circumvent the
+		// fact that, in a variantless build graph, "libc" has a dependency on itself.
+		if ctx.ModuleName() != "libc" {
+			ctx.AddDependency(ctx.Module(), Bp2buildDepTag, dep)
+		}
+	}
 	if !convertedToBazel(ctx, m) {
 		ctx.AddUnconvertedBp2buildDep(dep)
 	}
diff --git a/android/config.go b/android/config.go
index ed9b7b0..622a672 100644
--- a/android/config.go
+++ b/android/config.go
@@ -297,6 +297,10 @@
 	// in tests when a path doesn't exist.
 	TestAllowNonExistentPaths bool
 
+	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
+	// in tests when a path doesn't exist.
+	Bp2buildDepsMutator bool
+
 	// The list of files that when changed, must invalidate soong_build to
 	// regenerate build.ninja.
 	ninjaFileDepsSet sync.Map
@@ -1435,10 +1439,6 @@
 	return String(c.config.productVariables.Platform_vndk_version)
 }
 
-func (c *deviceConfig) ProductVndkVersion() string {
-	return String(c.config.productVariables.ProductVndkVersion)
-}
-
 func (c *deviceConfig) ExtraVndkVersions() []string {
 	return c.config.productVariables.ExtraVndkVersions
 }
diff --git a/android/filegroup.go b/android/filegroup.go
index b6e37a5..856c50e 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -50,7 +50,7 @@
 	// ignoring case, checks for proto or protos as an independent word in the name, whether at the
 	// beginning, end, or middle. e.g. "proto.foo", "bar-protos", "baz_proto_srcs" would all match
 	filegroupLikelyProtoPattern = regexp.MustCompile("(?i)(^|[^a-z])proto(s)?([^a-z]|$)")
-	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl([^a-z]|$)")
+	filegroupLikelyAidlPattern  = regexp.MustCompile("(?i)(^|[^a-z])aidl(s)?([^a-z]|$)")
 
 	ProtoSrcLabelPartition = bazel.LabelPartition{
 		Extensions:  []string{".proto"},
diff --git a/android/mutator.go b/android/mutator.go
index 57ff1e0..3d59655 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -35,6 +35,9 @@
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
 func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
 	bp2buildMutators := append(preArchMutators, registerBp2buildConversionMutator)
+	if ctx.config.Bp2buildDepsMutator {
+		bp2buildMutators = append(bp2buildMutators, registerBp2buildDepsMutator)
+	}
 	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
 }
 
@@ -226,6 +229,15 @@
 	BazelConversionPathContext
 	BaseMutatorContext
 
+	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
+	// dependency (some entries may be nil).
+	//
+	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
+	// new dependencies have had the current mutator called on them.  If the mutator is not
+	// parallel this method does not affect the ordering of the current mutator pass, but will
+	// be ordered correctly for all future mutator passes.
+	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
+
 	// CreateBazelTargetModule creates a BazelTargetModule by calling the
 	// factory method, just like in CreateModule, but also requires
 	// BazelTargetModuleProperties containing additional metadata for the
@@ -294,15 +306,6 @@
 	BaseMutatorContext
 	Bp2buildMutatorContext
 
-	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
-	// dependency (some entries may be nil).
-	//
-	// If the mutator is parallel (see MutatorHandle.Parallel), this method will pause until the
-	// new dependencies have had the current mutator called on them.  If the mutator is not
-	// parallel this method does not affect the ordering of the current mutator pass, but will
-	// be ordered correctly for all future mutator passes.
-	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module
-
 	// AddReverseDependency adds a dependency from the destination to the given module.
 	// Does not affect the ordering of the current mutator pass, but will be ordered
 	// correctly for all future mutator passes.  All reverse dependencies for a destination module are
diff --git a/android/register.go b/android/register.go
index f1c2986..6182159 100644
--- a/android/register.go
+++ b/android/register.go
@@ -181,8 +181,7 @@
 	return ctx
 }
 
-// Helper function to register the module types used in bp2build and
-// api_bp2build.
+// Helper function to register the module types used in bp2build.
 func registerModuleTypes(ctx *Context) {
 	for _, t := range moduleTypes {
 		t.register(ctx)
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 3a2cb1a..c33ade5 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -148,7 +148,7 @@
 		return
 	}
 	if !ok {
-		t.Errorf("%s does not match regular expression %s", s, expectedRex)
+		t.Errorf("%s: %s does not match regular expression %s", message, s, expectedRex)
 	}
 }
 
diff --git a/android/variable.go b/android/variable.go
index 3a5ad63..8882e80 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -418,8 +418,6 @@
 	ProductPublicSepolicyDirs  []string `json:",omitempty"`
 	ProductPrivateSepolicyDirs []string `json:",omitempty"`
 
-	ProductVndkVersion *string `json:",omitempty"`
-
 	TargetFSConfigGen []string `json:",omitempty"`
 
 	EnforceProductPartitionInterface *bool `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 090d9c4..f903373 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -736,7 +736,7 @@
 			vndkVersion = deviceConfig.VndkVersion()
 		} else if a.ProductSpecific() {
 			prefix = cc.ProductVariationPrefix
-			vndkVersion = deviceConfig.ProductVndkVersion()
+			vndkVersion = deviceConfig.PlatformVndkVersion()
 		}
 	}
 	if vndkVersion == "current" {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9475f5d..e70d3af 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -948,7 +948,7 @@
 	// Ensure that stub dependency from a rust module is not included
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
 	// The rust module is linked to the stub cc library
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 
@@ -1024,7 +1024,7 @@
 	mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
 	ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
 	ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"]
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 }
@@ -3088,10 +3088,7 @@
 			apex_available: ["myapex"],
 			srcs: ["foo.cpp"],
 		}
-	`, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.ProductVndkVersion = proptools.StringPtr("current")
-	}),
-	)
+	`)
 
 	cflags := strings.Fields(
 		ctx.ModuleForTests("foo", "android_product.29_arm64_armv8-a_myapex").Rule("cc").Args["cFlags"])
@@ -10521,6 +10518,7 @@
 			min_sdk_version: "29",
 			recovery_available: true,
 			vendor_available: true,
+			product_available: true,
 		}
 		api_imports {
 			name: "api_imports",
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 2b86e53..e2aee96 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -115,12 +115,7 @@
 	})
 
 	t.Run("VNDK APEX gathers only vendor variants even if product variants are available", func(t *testing.T) {
-		ctx := testApex(t, bp,
-			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-				// Now product variant is available
-				variables.ProductVndkVersion = proptools.StringPtr("current")
-			}),
-		)
+		ctx := testApex(t, bp)
 
 		files := getFiles(t, ctx, "com.android.vndk.current", "android_common")
 		ensureFileSrc(t, files, "lib/libfoo.so", "libfoo/android_vendor.29_arm_armv7-a-neon_shared/libfoo.so")
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index f53588d..53c37b9 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -576,7 +576,7 @@
 				Dir:  ctx.ModuleDir(m),
 				Deps: m.(*bootstrap.GoPackage).Deps(),
 			}
-		} else if moduleType == "ndk_headers" {
+		} else if moduleType == "ndk_headers" || moduleType == "versioned_ndk_headers" {
 			ndkHeaders = append(ndkHeaders, m)
 		}
 	})
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index afbfffa..dc56a17 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -2101,3 +2101,219 @@
 	})
 
 }
+
+func TestBp2buildDepsMutator_missingTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	}
+
+	custom {
+		name: "has_deps",
+	  arch_paths: [":has_missing_dep", ":foo"],
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing transitive dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_missingDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":exists"],
+	}
+	custom {
+		name: "exists",
+	}
+
+	custom {
+		name: "has_missing_dep",
+	  arch_paths: [":missing"],
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":exists"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"exists",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with missing direct dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedDirectDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{},
+		Description:          "Skipping conversion of a target with unconverted direct dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_unconvertedTransitiveDep(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":has_unconverted_dep", ":bar"],
+	}
+
+	custom {
+		name: "bar",
+	}
+
+	custom {
+		name: "has_unconverted_dep",
+	  arch_paths: [":unconvertible"],
+	}
+
+	custom {
+		name: "unconvertible",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: expectedBazelTargets,
+		Description:          "Skipping conversion of a target with unconverted transitive dep",
+		DepsMutator:          true,
+	})
+}
+
+func TestBp2buildDepsMutator_alreadyExistsBuildDeps(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":bar"],
+	}
+	custom {
+		name: "bar",
+	  arch_paths: [":checked_in"],
+	}
+	custom {
+		name: "checked_in",
+	  arch_paths: [":checked_in"],
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":bar"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{"arch_paths": `[":checked_in"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with already-existing build dep",
+		DepsMutator:             true,
+	})
+}
+
+// Tests that deps of libc are always considered valid for libc. This circumvents
+// an issue that, in a variantless graph (such as bp2build's), libc has the
+// unique predicament that it depends on itself.
+func TestBp2buildDepsMutator_depOnLibc(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+	  arch_paths: [":libc"],
+	}
+	custom {
+		name: "libc",
+	  arch_paths: [":libc_dep"],
+	}
+	custom {
+		name: "libc_dep",
+		does_not_convert_to_bazel: true
+	}
+	`
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"foo",
+			AttrNameToString{"arch_paths": `[":libc"]`},
+		),
+		MakeBazelTarget(
+			"custom",
+			"libc",
+			AttrNameToString{"arch_paths": `[":libc_dep"]`},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		StubbedBuildDefinitions: []string{"checked_in"},
+		Blueprint:               bp,
+		ExpectedBazelTargets:    expectedBazelTargets,
+		Description:             "Convert target with dep on libc",
+		DepsMutator:             true,
+	})
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 402d4b0..645298f 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -95,6 +95,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -128,6 +129,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
@@ -161,6 +163,7 @@
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "dir": attr.string(),
+        "does_not_convert_to_bazel": attr.bool(),
         "embedded_prop": attr.string(),
         "int64_ptr_prop": attr.int(),
         # nested_props start
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 3cce430..bc88f86 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -5198,7 +5198,7 @@
 	name: "libfoo_headers",
 	from: "from",
 	to: "to",
-	srcs: ["foo.h", "foo_other.h"]
+	srcs: ["from/foo.h", "from/foo_other.h"]
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -5206,11 +5206,42 @@
 				"strip_import_prefix": `"from"`,
 				"import_prefix":       `"to"`,
 				"hdrs": `[
-        "foo.h",
-        "foo_other.h",
+        "from/foo.h",
+        "from/foo_other.h",
     ]`,
 			}),
 		},
 	}
 	runCcLibraryTestCase(t, tc)
 }
+
+func TestVersionedNdkHeadersConversion(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "versioned_ndk_headers conversion",
+		ModuleTypeUnderTest:        "versioned_ndk_headers",
+		ModuleTypeUnderTestFactory: cc.VersionedNdkHeadersFactory,
+		Blueprint: `
+versioned_ndk_headers {
+	name: "libfoo_headers",
+	from: "from",
+	to: "to",
+}
+`,
+		Filesystem: map[string]string{
+			"from/foo.h":       "",
+			"from/foo_other.h": "",
+		},
+		ExpectedBazelTargets: []string{
+			MakeBazelTargetNoRestrictions("ndk_headers", "libfoo_headers", AttrNameToString{
+				"strip_import_prefix": `"from"`,
+				"import_prefix":       `"to"`,
+				"hdrs": `[
+        "from/foo.h",
+        "from/foo_other.h",
+    ]`,
+				"run_versioner": "True",
+			}),
+		},
+	}
+	runCcLibraryTestCase(t, tc)
+}
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 7e4e44e..38571d4 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -567,12 +567,20 @@
 		"b.aidl",
 	],
 }
+filegroup {
+	name: "aidls_files",
+	srcs: [
+		"a.aidl",
+		"b.aidl",
+	],
+}
 java_library {
 	name: "example_lib",
 	srcs: [
 		"a.java",
 		"b.java",
 		":aidl_files",
+		":aidls_files",
 		":random_other_files",
 	],
 	sdk_version: "current",
@@ -586,8 +594,18 @@
     ]`,
 				"tags": `["apex_available=//apex_available:anyapex"]`,
 			}),
+			MakeBazelTargetNoRestrictions("aidl_library", "aidls_files", AttrNameToString{
+				"srcs": `[
+        "a.aidl",
+        "b.aidl",
+    ]`,
+				"tags": `["apex_available=//apex_available:anyapex"]`,
+			}),
 			MakeBazelTarget("java_aidl_library", "example_lib_java_aidl_library", AttrNameToString{
-				"deps": `[":aidl_files"]`,
+				"deps": `[
+        ":aidl_files",
+        ":aidls_files",
+    ]`,
 			}),
 			MakeBazelTarget("java_library", "example_lib", AttrNameToString{
 				"deps":    `[":example_lib_java_aidl_library"]`,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index d26b346..6907487 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -124,25 +124,37 @@
 	// be merged with the generated BUILD file. This allows custom BUILD targets
 	// to be used in tests, or use BUILD files to draw package boundaries.
 	KeepBuildFileForDirs []string
+
+	// If true, the bp2build_deps mutator is used for this test. This is an
+	// experimental mutator that will disable modules which have transitive
+	// dependencies with no bazel definition.
+	// TODO: b/285631638 - Enable this feature by default.
+	DepsMutator bool
 }
 
 func RunBp2BuildTestCaseExtraContext(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), modifyContext func(ctx *android.TestContext), tc Bp2buildTestCase) {
 	t.Helper()
-	bp2buildSetup := android.GroupFixturePreparers(
+	preparers := []android.FixturePreparer{
 		android.FixtureRegisterWithContext(registerModuleTypes),
-		android.FixtureModifyContext(modifyContext),
-		SetBp2BuildTestRunner,
+	}
+	if modifyContext != nil {
+		preparers = append(preparers, android.FixtureModifyContext(modifyContext))
+	}
+	if tc.DepsMutator {
+		preparers = append(preparers, android.FixtureModifyConfig(func(cfg android.Config) {
+			cfg.Bp2buildDepsMutator = true
+		}))
+	}
+	preparers = append(preparers, SetBp2BuildTestRunner)
+	bp2buildSetup := android.GroupFixturePreparers(
+		preparers...,
 	)
 	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
 }
 
 func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
 	t.Helper()
-	bp2buildSetup := android.GroupFixturePreparers(
-		android.FixtureRegisterWithContext(registerModuleTypes),
-		SetBp2BuildTestRunner,
-	)
-	runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
+	RunBp2BuildTestCaseExtraContext(t, registerModuleTypes, nil, tc)
 }
 
 func runBp2BuildTestCaseWithSetup(t *testing.T, extraPreparer android.FixturePreparer, tc Bp2buildTestCase) {
@@ -400,6 +412,10 @@
 	// Prop used to indicate this conversion should be 1 module -> multiple targets
 	One_to_many_prop *bool
 
+	// Prop used to simulate an unsupported property in bp2build conversion. If this
+	// is true, this module should be treated as "unconvertible" via bp2build.
+	Does_not_convert_to_bazel *bool
+
 	Api *string // File describing the APIs of this module
 
 	Test_config_setting *bool // Used to test generation of config_setting targets
@@ -535,6 +551,10 @@
 }
 
 func (m *customModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	if p := m.props.Does_not_convert_to_bazel; p != nil && *p {
+		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_PROPERTY_UNSUPPORTED, "")
+		return
+	}
 	if p := m.props.One_to_many_prop; p != nil && *p {
 		customBp2buildOneToMany(ctx, m)
 		return
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 7738487..45fbf27 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -99,7 +99,7 @@
 	Tidy_timeout_srcs     bazel.LabelListAttribute
 }
 
-func (m *Module) convertTidyAttributes(ctx android.BaseMutatorContext, moduleAttrs *tidyAttributes) {
+func (m *Module) convertTidyAttributes(ctx android.Bp2buildMutatorContext, moduleAttrs *tidyAttributes) {
 	for _, f := range m.features {
 		if tidy, ok := f.(*tidyFeature); ok {
 			var tidyAttr *string
@@ -246,9 +246,9 @@
 	implementation bazel.LabelList
 }
 
-type bazelLabelForDepsFn func(android.BazelConversionPathContext, []string) bazel.LabelList
+type bazelLabelForDepsFn func(android.Bp2buildMutatorContext, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDeps(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
+func maybePartitionExportedAndImplementationsDeps(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, exportedDeps []string, fn bazelLabelForDepsFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps),
@@ -263,9 +263,9 @@
 	}
 }
 
-type bazelLabelForDepsExcludesFn func(android.BazelConversionPathContext, []string, []string) bazel.LabelList
+type bazelLabelForDepsExcludesFn func(android.Bp2buildMutatorContext, []string, []string) bazel.LabelList
 
-func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.BazelConversionPathContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
+func maybePartitionExportedAndImplementationsDepsExcludes(ctx android.Bp2buildMutatorContext, exportsDeps bool, allDeps, excludes, exportedDeps []string, fn bazelLabelForDepsExcludesFn) depsPartition {
 	if !exportsDeps {
 		return depsPartition{
 			implementation: fn(ctx, allDeps, excludes),
@@ -352,7 +352,7 @@
 	Enabled bazel.BoolAttribute
 }
 
-func parseSrc(ctx android.BazelConversionPathContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
+func parseSrc(ctx android.Bp2buildMutatorContext, srcLabelAttribute *bazel.LabelAttribute, axis bazel.ConfigurationAxis, config string, srcs []string) {
 	srcFileError := func() {
 		ctx.ModuleErrorf("parseSrc: Expected at most one source file for %s %s\n", axis, config)
 	}
@@ -370,7 +370,7 @@
 }
 
 // NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
-func Bp2BuildParsePrebuiltLibraryProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) prebuiltAttributes {
+func Bp2BuildParsePrebuiltLibraryProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) prebuiltAttributes {
 
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
@@ -407,7 +407,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltBinaryProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltBinaryProps(ctx android.Bp2buildMutatorContext, module *Module) prebuiltAttributes {
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltLinkerProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if props, ok := props.(*prebuiltLinkerProperties); ok {
@@ -420,7 +420,7 @@
 	}
 }
 
-func bp2BuildParsePrebuiltObjectProps(ctx android.BazelConversionPathContext, module *Module) prebuiltAttributes {
+func bp2BuildParsePrebuiltObjectProps(ctx android.Bp2buildMutatorContext, module *Module) prebuiltAttributes {
 	var srcLabelAttribute bazel.LabelAttribute
 	bp2BuildPropParseHelper(ctx, module, &prebuiltObjectProperties{}, func(axis bazel.ConfigurationAxis, config string, props interface{}) {
 		if props, ok := props.(*prebuiltObjectProperties); ok {
@@ -555,7 +555,7 @@
 	return result
 }
 
-func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
+func (ca *compilerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis, config string, props *BaseCompilerProperties) {
 	// If there's arch specific srcs or exclude_srcs, generate a select entry for it.
 	// TODO(b/186153868): do this for OS specific srcs and exclude_srcs too.
 	srcsList, ok := parseSrcs(ctx, props)
@@ -680,7 +680,7 @@
 }
 
 // Parse srcs from an arch or OS's props value.
-func parseSrcs(ctx android.BazelConversionPathContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
+func parseSrcs(ctx android.Bp2buildMutatorContext, props *BaseCompilerProperties) (bazel.LabelList, bool) {
 	anySrcs := false
 	// Add srcs-like dependencies such as generated files.
 	// First create a LabelList containing these dependencies, then merge the values with srcs.
@@ -1265,7 +1265,7 @@
 
 // resolveTargetApex re-adds the shared and static libs in target.apex.exclude_shared|static_libs props to non-apex variant
 // since all libs are already excluded by default
-func (la *linkerAttributes) resolveTargetApexProp(ctx android.BazelConversionPathContext, props *BaseLinkerProperties) {
+func (la *linkerAttributes) resolveTargetApexProp(ctx android.Bp2buildMutatorContext, props *BaseLinkerProperties) {
 	excludeSharedLibs := bazelLabelForSharedDeps(ctx, props.Target.Apex.Exclude_shared_libs)
 	sharedExcludes := bazel.LabelList{Excludes: excludeSharedLibs.Includes}
 	sharedExcludesLabelList := bazel.LabelListAttribute{}
@@ -1696,7 +1696,7 @@
 	})
 }
 
-func (la *linkerAttributes) convertProductVariables(ctx android.BazelConversionPathContext, productVariableProps android.ProductConfigProperties) {
+func (la *linkerAttributes) convertProductVariables(ctx android.Bp2buildMutatorContext, productVariableProps android.ProductConfigProperties) {
 
 	type productVarDep struct {
 		// the name of the corresponding excludes field, if one exists
@@ -1704,7 +1704,7 @@
 		// reference to the bazel attribute that should be set for the given product variable config
 		attribute *bazel.LabelListAttribute
 
-		depResolutionFunc func(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList
+		depResolutionFunc func(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList
 	}
 
 	// an intermediate attribute that holds Header_libs info, and will be appended to
@@ -1762,7 +1762,7 @@
 	la.implementationDeps.Append(headerDeps)
 }
 
-func (la *linkerAttributes) finalize(ctx android.BazelConversionPathContext) {
+func (la *linkerAttributes) finalize(ctx android.Bp2buildMutatorContext) {
 	// if system dynamic deps have the default value, any use of a system dynamic library used will
 	// result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
 	// from bionic OSes and the no config case as these libraries only build for bionic OSes.
@@ -1903,39 +1903,39 @@
 	return xsd.CppBp2buildTargetName()
 }
 
-func bazelLabelForWholeDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps)
+func bazelLabelForWholeDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticWholeModuleDeps, true)
 }
 
-func bazelLabelForWholeDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForWholeDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticWholeModuleDeps)
 }
 
-func bazelLabelForStaticDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForStaticDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForStaticModule)
 }
 
-func bazelLabelForStaticDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule)
+func bazelLabelForStaticDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForStaticModule, true)
 }
 
-func bazelLabelForSharedDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
-	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule)
+func bazelLabelForSharedDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
+	return android.BazelLabelForModuleDepsWithFn(ctx, modules, bazelLabelForSharedModule, true)
 }
 
-func bazelLabelForHeaderDeps(ctx android.BazelConversionPathContext, modules []string) bazel.LabelList {
+func bazelLabelForHeaderDeps(ctx android.Bp2buildMutatorContext, modules []string) bazel.LabelList {
 	// This is not elegant, but bp2build's shared library targets only propagate
 	// their header information as part of the normal C++ provider.
 	return bazelLabelForSharedDeps(ctx, modules)
 }
 
-func bazelLabelForHeaderDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForHeaderDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	// This is only used when product_variable header_libs is processed, to follow
 	// the pattern of depResolutionFunc
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
 
-func bazelLabelForSharedDepsExcludes(ctx android.BazelConversionPathContext, modules, excludes []string) bazel.LabelList {
+func bazelLabelForSharedDepsExcludes(ctx android.Bp2buildMutatorContext, modules, excludes []string) bazel.LabelList {
 	return android.BazelLabelForModuleDepsExcludesWithFn(ctx, modules, excludes, bazelLabelForSharedModule)
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 1896766..8c248f9 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1895,8 +1895,7 @@
 			// do not add a name suffix because it is a base module.
 			return ""
 		}
-		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
-		nameSuffix = ProductSuffix
+		return ProductSuffix
 	} else {
 		vndkVersion = ctx.DeviceConfig().VndkVersion()
 		nameSuffix = VendorSuffix
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7ce0f37..f7eb8d2 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -41,7 +41,6 @@
 	PrepareForTestWithCcIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -104,33 +103,6 @@
 	return result.TestContext
 }
 
-// testCcNoVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
-// testCcNoProductVndk runs tests using the prepareForCcTest
-//
-// See testCc for an explanation as to how to stop using this deprecated method.
-//
-// deprecated
-func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext {
-	t.Helper()
-	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
-	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
-
-	return testCcWithConfig(t, config)
-}
-
 // testCcErrorWithConfig runs tests using the prepareForCcTest
 //
 // See testCc for an explanation as to how to stop using this deprecated method.
@@ -167,7 +139,6 @@
 	t.Helper()
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 	testCcErrorWithConfig(t, pattern, config)
 	return
@@ -523,7 +494,6 @@
 
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
@@ -889,63 +859,6 @@
 	}
 }
 
-func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-		cc_library {
-			name: "libvndk-private",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-				private: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libllndk",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-				export_llndk_headers: ["libllndk_headers"],
-			}
-		}
-
-		cc_library_headers {
-			name: "libllndk_headers",
-			llndk: {
-				symbol_file: "libllndk.map.txt",
-			},
-			export_include_dirs: ["include"],
-		}
-	`)
-
-	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
-		"LLNDK: libc.so",
-		"LLNDK: libdl.so",
-		"LLNDK: libft2.so",
-		"LLNDK: libllndk.so",
-		"LLNDK: libm.so",
-		"VNDK-SP: libc++.so",
-		"VNDK-core: libvndk-private.so",
-		"VNDK-core: libvndk.so",
-		"VNDK-private: libft2.so",
-		"VNDK-private: libvndk-private.so",
-		"VNDK-product: libc++.so",
-		"VNDK-product: libvndk-private.so",
-		"VNDK-product: libvndk.so",
-	})
-}
-
 func TestVndkModuleError(t *testing.T) {
 	t.Parallel()
 	// Check the error message for vendor_available and product_available properties.
@@ -1111,6 +1024,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1132,6 +1046,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1153,6 +1068,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1175,6 +1091,7 @@
 		cc_library {
 			name: "libnonvndk",
 			vendor_available: true,
+			product_available: true,
 			nocrt: true,
 		}
 	`)
@@ -1390,6 +1307,7 @@
 		cc_library {
 			name: "libanothervndksp",
 			vendor_available: true,
+			product_available: true,
 		}
 	`)
 }
@@ -1467,7 +1385,6 @@
 	`
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	ctx := testCcWithConfig(t, config)
@@ -1482,70 +1399,6 @@
 	assertString(t, mod_product.outputFile.Path().Base(), "libvndk2-suffix.so")
 }
 
-func TestVndkExtWithoutBoardVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set.
-	ctx := testCcNoVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext",
-			vendor: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
-func TestVndkExtWithoutProductVndkVersion(t *testing.T) {
-	t.Parallel()
-	// This test checks the VNDK-Ext properties when PRODUCT_PRODUCT_VNDK_VERSION is not set.
-	ctx := testCcNoProductVndk(t, `
-		cc_library {
-			name: "libvndk",
-			vendor_available: true,
-			product_available: true,
-			vndk: {
-				enabled: true,
-			},
-			nocrt: true,
-		}
-
-		cc_library {
-			name: "libvndk_ext_product",
-			product_specific: true,
-			vndk: {
-				enabled: true,
-				extends: "libvndk",
-			},
-			nocrt: true,
-		}
-	`)
-
-	// Ensures that the core variant of "libvndk_ext_product" can be found.
-	mod := ctx.ModuleForTests("libvndk_ext_product", coreVariant).Module().(*Module)
-	if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
-		t.Errorf("\"libvndk_ext_product\" must extend from \"libvndk\" but get %q", extends)
-	}
-}
-
 func TestVndkExtError(t *testing.T) {
 	t.Parallel()
 	// This test ensures an error is emitted in ill-formed vndk-ext definition.
@@ -1920,7 +1773,6 @@
 	`
 	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
-	config.TestProductVariables.ProductVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("29")
 
 	testCcWithConfig(t, config)
@@ -3034,24 +2886,6 @@
 	checkRuntimeLibs(t, nil, module)
 }
 
-func TestRuntimeLibsNoVndk(t *testing.T) {
-	t.Parallel()
-	ctx := testCcNoVndk(t, runtimeLibAndroidBp)
-
-	// If DeviceVndkVersion is not defined, then runtime_libs are copied as-is.
-
-	variant := "android_arm64_armv8-a_shared"
-
-	module := ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available"}, module)
-
-	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module)
-
-	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module)
-}
-
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
 	t.Helper()
 	actual := module.Properties.AndroidMkStaticLibs
diff --git a/cc/genrule.go b/cc/genrule.go
index d1c4c2a..63c728c 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -84,7 +84,7 @@
 		return true
 	}
 
-	if ctx.DeviceConfig().ProductVndkVersion() != "" && ctx.ProductSpecific() {
+	if ctx.ProductSpecific() {
 		return false
 	}
 
@@ -134,15 +134,8 @@
 		}
 	}
 
-	if ctx.DeviceConfig().ProductVndkVersion() == "" {
-		return variants
-	}
-
 	if Bool(g.Product_available) || ctx.ProductSpecific() {
 		variants = append(variants, ProductVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		if vndkVersion := ctx.DeviceConfig().ProductVndkVersion(); vndkVersion != "current" {
-			variants = append(variants, ProductVariationPrefix+vndkVersion)
-		}
 	}
 
 	return variants
diff --git a/cc/image.go b/cc/image.go
index f91762a..239f1db 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -427,7 +427,6 @@
 
 	platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
 	boardVndkVersion := mctx.DeviceConfig().VndkVersion()
-	productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
 	recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion()
 	usingRecoverySnapshot := recoverySnapshotVersion != "current" &&
 		recoverySnapshotVersion != ""
@@ -444,9 +443,6 @@
 	if boardVndkVersion == "current" {
 		boardVndkVersion = platformVndkVersion
 	}
-	if productVndkVersion == "current" {
-		productVndkVersion = platformVndkVersion
-	}
 
 	if m.NeedsLlndkVariants() {
 		// This is an LLNDK library.  The implementation of the library will be on /system,
@@ -462,9 +458,6 @@
 		if needVndkVersionVendorVariantForLlndk {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
 		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
-		}
 	} else if m.NeedsVendorPublicLibraryVariants() {
 		// A vendor public library has the implementation on /vendor, with stub variants
 		// for system and product.
@@ -473,9 +466,6 @@
 		if platformVndkVersion != "" {
 			productVariants = append(productVariants, platformVndkVersion)
 		}
-		if productVndkVersion != "" {
-			productVariants = append(productVariants, productVndkVersion)
-		}
 	} else if boardVndkVersion == "" {
 		// If the device isn't compiling against the VNDK, we always
 		// use the core mode.
@@ -507,10 +497,6 @@
 		// product_available modules are available to /product.
 		if m.HasProductVariant() {
 			productVariants = append(productVariants, platformVndkVersion)
-			// VNDK is always PLATFORM_VNDK_VERSION
-			if !m.IsVndk() {
-				productVariants = append(productVariants, productVndkVersion)
-			}
 		}
 	} else if vendorSpecific && m.SdkVersion() == "" {
 		// This will be available in /vendor (or /odm) only
@@ -538,17 +524,10 @@
 		coreVariantNeeded = true
 	}
 
-	if boardVndkVersion != "" && productVndkVersion != "" {
-		if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
-			// The module has "product_specific: true" that does not create core variant.
-			coreVariantNeeded = false
-			productVariants = append(productVariants, productVndkVersion)
-		}
-	} else {
-		// Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no
-		// restriction to use system libs.
-		// No product variants defined in this case.
-		productVariants = []string{}
+	if coreVariantNeeded && productSpecific && m.SdkVersion() == "" {
+		// The module has "product_specific: true" that does not create core variant.
+		coreVariantNeeded = false
+		productVariants = append(productVariants, platformVndkVersion)
 	}
 
 	if m.RamdiskAvailable() {
diff --git a/cc/library.go b/cc/library.go
index e66ce08..90d91ca 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -547,54 +547,6 @@
 	includes.attrs.Deps.Append(lla)
 }
 
-// includes provided to the module-lib API surface. This API surface is used by apexes.
-func getModuleLibApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	flagProps := c.library.(*libraryDecorator).flagExporter.Properties
-	linkProps := c.library.(*libraryDecorator).baseLinker.Properties
-	includes := android.FirstUniqueStrings(flagProps.Export_include_dirs)
-	systemIncludes := android.FirstUniqueStrings(flagProps.Export_system_include_dirs)
-	headerLibs := android.FirstUniqueStrings(linkProps.Export_header_lib_headers)
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, headerLibs)),
-	}
-
-	return apiIncludes{
-		name: c.Name() + ".module-libapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
-func getVendorApiIncludes(ctx android.TopDownMutatorContext, c *Module) apiIncludes {
-	baseProps := c.library.(*libraryDecorator).flagExporter.Properties
-	llndkProps := c.library.(*libraryDecorator).Properties.Llndk
-	includes := baseProps.Export_include_dirs
-	systemIncludes := baseProps.Export_system_include_dirs
-	// LLNDK can override the base includes
-	if llndkIncludes := llndkProps.Override_export_include_dirs; llndkIncludes != nil {
-		includes = llndkIncludes
-	}
-	if proptools.Bool(llndkProps.Export_headers_as_system) {
-		systemIncludes = append(systemIncludes, includes...)
-		includes = nil
-	}
-
-	attrs := bazelCcLibraryHeadersAttributes{
-		Export_includes:        bazel.MakeStringListAttribute(includes),
-		Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		Deps:                   bazel.MakeLabelListAttribute(apiHeaderLabels(ctx, llndkProps.Export_llndk_headers)),
-	}
-	return apiIncludes{
-		name: c.Name() + ".vendorapi.headers",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: attrs,
-		},
-	}
-}
-
 // cc_library creates both static and/or shared libraries for a device and/or
 // host. By default, a cc_library has a single variant that targets the device.
 // Specifying `host_supported: true` also creates a library that targets the
diff --git a/cc/library_headers.go b/cc/library_headers.go
index fccdf99..4da2b48 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -161,18 +161,3 @@
 		Tags: tags,
 	}, attrs)
 }
-
-// Append .contribution suffix to input labels
-func apiBazelTargets(ll bazel.LabelList) bazel.LabelList {
-	labels := make([]bazel.Label, 0)
-	for _, l := range ll.Includes {
-		labels = append(labels, bazel.Label{
-			Label: android.ApiContributionTargetName(l.Label),
-		})
-	}
-	return bazel.MakeLabelList(labels)
-}
-
-var (
-	allArches = []string{"arm", "arm64", "x86", "x86_64"}
-)
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index da5db1c..461aa96 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -19,6 +19,7 @@
 	"path/filepath"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
 	"android/soong/bazel"
@@ -151,6 +152,7 @@
 	Strip_import_prefix *string
 	Import_prefix       *string
 	Hdrs                bazel.LabelListAttribute
+	Run_versioner       *bool
 }
 
 func (h *headerModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
@@ -217,6 +219,7 @@
 // Note that this is really only built to handle bionic/libc/include.
 type versionedHeaderModule struct {
 	android.ModuleBase
+	android.BazelModuleBase
 
 	properties versionedHeaderProperties
 
@@ -255,6 +258,25 @@
 	processHeadersWithVersioner(ctx, fromSrcPath, toOutputPath, m.srcPaths, installPaths)
 }
 
+func (h *versionedHeaderModule) ConvertWithBp2build(ctx android.Bp2buildMutatorContext) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "ndk_headers",
+		Bzl_load_location: "//build/bazel/rules/cc:ndk_headers.bzl",
+	}
+	globPattern := headerGlobPattern(proptools.String(h.properties.From))
+	attrs := &bazelNdkHeadersAttributes{
+		Strip_import_prefix: h.properties.From,
+		Import_prefix:       h.properties.To,
+		Run_versioner:       proptools.BoolPtr(true),
+		Hdrs:                bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, []string{globPattern})),
+	}
+	ctx.CreateBazelTargetModule(
+		props,
+		android.CommonAttributes{Name: h.Name()},
+		attrs,
+	)
+}
+
 func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir android.Path,
 	srcPaths android.Paths, installPaths []android.WritablePath) android.Path {
 	// The versioner depends on a dependencies directory to simplify determining include paths
@@ -298,12 +320,13 @@
 // Unlike the ndk_headers soong module, versioned_ndk_headers operates on a
 // directory level specified in `from` property. This is only used to process
 // the bionic/libc/include directory.
-func versionedNdkHeadersFactory() android.Module {
+func VersionedNdkHeadersFactory() android.Module {
 	module := &versionedHeaderModule{}
 
 	module.AddProperties(&module.properties)
 
 	android.InitAndroidModule(module)
+	android.InitBazelModule(module)
 
 	return module
 }
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 56c57b9..2064b1b 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -61,7 +61,7 @@
 			// because we don't want to spam the build output with "nothing
 			// changed" messages, so redirect output message to $out, and if
 			// changes were detected print the output and fail.
-			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+			Command:     "$stgdiff $args --stg $in -o $out || (cat $out && false; echo 'Run $$ANDROID_BUILD_TOP/development/tools/ndk/update_ndk_abi.sh to update the ABI dumps.')",
 			CommandDeps: []string{"$stgdiff"},
 		}, "args")
 
@@ -580,15 +580,6 @@
 	Library_name string
 }
 
-// Names of the cc_api_header targets in the bp2build workspace
-func apiHeaderLabels(ctx android.TopDownMutatorContext, hdrLibs []string) bazel.LabelList {
-	addSuffix := func(ctx android.BazelConversionPathContext, module blueprint.Module) string {
-		label := android.BazelModuleLabel(ctx, module)
-		return android.ApiContributionTargetName(label)
-	}
-	return android.BazelLabelForModuleDepsWithFn(ctx, hdrLibs, addSuffix)
-}
-
 func ndkLibraryBp2build(ctx android.Bp2buildMutatorContext, c *Module) {
 	ndk, _ := c.linker.(*stubDecorator)
 	props := bazel.BazelTargetModuleProperties{
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index 54a2ee2..483d23b 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -64,7 +64,7 @@
 func RegisterNdkModuleTypes(ctx android.RegistrationContext) {
 	ctx.RegisterModuleType("ndk_headers", NdkHeadersFactory)
 	ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
-	ctx.RegisterModuleType("versioned_ndk_headers", versionedNdkHeadersFactory)
+	ctx.RegisterModuleType("versioned_ndk_headers", VersionedNdkHeadersFactory)
 	ctx.RegisterModuleType("preprocessed_ndk_headers", preprocessedNdkHeadersFactory)
 	ctx.RegisterParallelSingletonType("ndk", NdkSingleton)
 }
diff --git a/cc/test.go b/cc/test.go
index 8c63dc6..f128187 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -799,7 +799,7 @@
 
 // cc_test that builds using gtest needs some additional deps
 // addImplicitGtestDeps makes these deps explicit in the generated BUILD files
-func addImplicitGtestDeps(ctx android.BazelConversionPathContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
+func addImplicitGtestDeps(ctx android.Bp2buildMutatorContext, attrs *testBinaryAttributes, gtest, gtestIsolated bool) {
 	addDepsAndDedupe := func(lla *bazel.LabelListAttribute, modules []string) {
 		moduleLabels := android.BazelLabelForModuleDeps(ctx, modules)
 		lla.Value.Append(moduleLabels)
diff --git a/java/config/kotlin.go b/java/config/kotlin.go
index fc63f4d..e5e187c 100644
--- a/java/config/kotlin.go
+++ b/java/config/kotlin.go
@@ -49,8 +49,5 @@
 		"-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704
 	}, " "))
 
-	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{
-		// b/222162908: prevent kotlinc from reading /tmp/build.txt
-		"-Didea.plugins.compatible.build=999.SNAPSHOT",
-	}, " "))
+	pctx.StaticVariable("KotlincGlobalFlags", strings.Join([]string{}, " "))
 }
diff --git a/java/dex.go b/java/dex.go
index 3468a70..348c939 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -140,9 +140,7 @@
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
 			`rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` +
 			`mkdir -p $$(dirname ${outUsage}) && ` +
-			`mkdir -p $$(dirname $tmpJar) && ` +
-			`${config.Zip2ZipCmd} -i $in -o $tmpJar -x '**/*.dex' && ` +
-			`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $tmpJar --output $outDir ` +
+			`$r8Template${config.R8Cmd} ${config.R8Flags} -injars $in --output $outDir ` +
 			`--no-data-resources ` +
 			`-printmapping ${outDict} ` +
 			`-printconfiguration ${outConfig} ` +
@@ -154,7 +152,7 @@
 			`rm -rf ${outUsageDir} && ` +
 			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
 			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
-			`rm -f "$tmpJar" "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
+			`rm -f "$outDir/classes*.dex" "$outDir/classes.dex.jar"`,
 		Depfile: "${out}.d",
 		Deps:    blueprint.DepsGCC,
 		CommandDeps: []string{
@@ -187,7 +185,7 @@
 			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
 		},
 	}, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir",
-		"r8Flags", "zipFlags", "tmpJar", "mergeZipsFlags"}, []string{"implicits"})
+		"r8Flags", "zipFlags", "mergeZipsFlags"}, []string{"implicits"})
 
 func (d *dexer) dexCommonFlags(ctx android.ModuleContext,
 	dexParams *compileDexParams) (flags []string, deps android.Paths) {
@@ -370,7 +368,6 @@
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
 	outDir := android.PathForModuleOut(ctx, "dex")
-	tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
 
 	zipFlags := "--ignore_missing_files"
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
@@ -408,7 +405,6 @@
 			"outUsage":       proguardUsage.String(),
 			"outUsageZip":    proguardUsageZip.String(),
 			"outDir":         outDir.String(),
-			"tmpJar":         tmpJar.String(),
 			"mergeZipsFlags": mergeZipsFlags,
 		}
 		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
@@ -428,6 +424,7 @@
 			Args:      args,
 		})
 	} else {
+		tmpJar := android.PathForModuleOut(ctx, "withres-withoutdex", dexParams.jarName)
 		d8Flags, d8Deps := d8Flags(dexParams.flags)
 		d8Deps = append(d8Deps, commonDeps...)
 		rule := d8
diff --git a/java/droiddoc.go b/java/droiddoc.go
index d5547d0..87588f3 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -136,6 +136,9 @@
 	// At some point, this might be improved to show more warnings.
 	Todo_file *string `android:"path"`
 
+	// A file containing a baseline for allowed lint errors.
+	Lint_baseline *string `android:"path"`
+
 	// directory under current module source that provide additional resources (images).
 	Resourcesdir *string
 
@@ -665,6 +668,10 @@
 			ImplicitOutput(android.PathForModuleOut(ctx, String(d.properties.Todo_file)))
 	}
 
+	if String(d.properties.Lint_baseline) != "" {
+		cmd.FlagWithInput("-lintbaseline ", android.PathForModuleSrc(ctx, String(d.properties.Lint_baseline)))
+	}
+
 	if String(d.properties.Resourcesdir) != "" {
 		// TODO: should we add files under resourcesDir to the implicits? It seems that
 		// resourcesDir is one sub dir of htmlDir
diff --git a/rust/binary.go b/rust/binary.go
index aee4da6..860dc94 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -77,14 +77,11 @@
 func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseCompiler.compilerFlags(ctx, flags)
 
-	if ctx.Os().Linux() {
-		flags.LinkFlags = append(flags.LinkFlags, "-Wl,--gc-sections")
-	}
-
 	if ctx.toolchain().Bionic() {
 		// no-undefined-version breaks dylib compilation since __rust_*alloc* functions aren't defined,
 		// but we can apply this to binaries.
 		flags.LinkFlags = append(flags.LinkFlags,
+			"-Wl,--gc-sections",
 			"-Wl,-z,nocopyreloc",
 			"-Wl,--no-undefined-version")
 
@@ -149,7 +146,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
-	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := outputFile
diff --git a/rust/binary_test.go b/rust/binary_test.go
index dff94ac..ef93037 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -150,7 +150,7 @@
 			bootstrap: true,
 		}`)
 
-	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink")
+	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
 	if !strings.Contains(foo.Args["linkFlags"], flag) {
@@ -167,11 +167,10 @@
 		}`)
 
 	fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
-	fizzOutLink := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustLink")
 	fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
 
 	flags := fizzOut.Args["rustcFlags"]
-	linkFlags := fizzOutLink.Args["linkFlags"]
+	linkFlags := fizzOut.Args["linkFlags"]
 	if !strings.Contains(flags, "-C relocation-model=static") {
 		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
@@ -201,7 +200,7 @@
 			name: "libfoo",
 		}`)
 
-	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink")
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
 	linkFlags := fizzBuzz.Args["linkFlags"]
 	if !strings.Contains(linkFlags, "/libfoo.so") {
 		t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
diff --git a/rust/builder.go b/rust/builder.go
index 9614d4f..bea8ff7 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -26,14 +26,14 @@
 
 var (
 	_     = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
-	_     = pctx.SourcePathVariable("mkcraterspCmd", "build/soong/scripts/mkcratersp.py")
 	rustc = pctx.AndroidStaticRule("rustc",
 		blueprint.RuleParams{
 			Command: "$envVars $rustcCmd " +
-				"-C linker=$mkcraterspCmd " +
+				"-C linker=${config.RustLinker} " +
+				"-C link-args=\"${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " +
 				"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
 				" && grep \"^$out:\" $out.d.raw > $out.d",
-			CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"},
+			CommandDeps: []string{"$rustcCmd"},
 			// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
 			// Rustc emits unneeded dependency lines for the .d and input .rs files.
 			// Those extra lines cause ninja warning:
@@ -42,12 +42,7 @@
 			Deps:    blueprint.DepsGCC,
 			Depfile: "$out.d",
 		},
-		"rustcFlags", "libFlags", "envVars")
-	rustLink = pctx.AndroidStaticRule("rustLink",
-		blueprint.RuleParams{
-			Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}",
-		},
-		"earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd")
+		"rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 
 	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
 	rustdoc = pctx.AndroidStaticRule("rustdoc",
@@ -106,13 +101,14 @@
 				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
 				`$rustExtractor $envVars ` +
 				`$rustcCmd ` +
-				`-C linker=true ` +
+				`-C linker=${config.RustLinker} ` +
+				`-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` +
 				`$in ${libFlags} $rustcFlags`,
 			CommandDeps:    []string{"$rustExtractor", "$kytheVnames"},
 			Rspfile:        "${out}.rsp",
 			RspfileContent: "$in",
 		},
-		"rustcFlags", "libFlags", "envVars")
+		"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
 )
 
 type buildOutput struct {
@@ -242,12 +238,6 @@
 		}
 	}
 
-	envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
-
-	if ctx.Darwin() {
-		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
-	}
-
 	return envVars
 }
 
@@ -255,7 +245,8 @@
 	outputFile android.WritablePath, crateType string) buildOutput {
 
 	var inputs android.Paths
-	var implicits, linkImplicits, linkOrderOnly android.Paths
+	var implicits android.Paths
+	var orderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
 	var earlyLinkFlags string
@@ -319,15 +310,15 @@
 	implicits = append(implicits, rustLibsToPaths(deps.RLibs)...)
 	implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...)
 	implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
-	implicits = append(implicits, deps.AfdoProfiles...)
+	implicits = append(implicits, deps.StaticLibs...)
+	implicits = append(implicits, deps.SharedLibDeps...)
 	implicits = append(implicits, deps.srcProviderFiles...)
-	implicits = append(implicits, deps.WholeStaticLibs...)
+	implicits = append(implicits, deps.AfdoProfiles...)
 
-	linkImplicits = append(linkImplicits, deps.LibDeps...)
-	linkImplicits = append(linkImplicits, deps.CrtBegin...)
-	linkImplicits = append(linkImplicits, deps.CrtEnd...)
+	implicits = append(implicits, deps.CrtBegin...)
+	implicits = append(implicits, deps.CrtEnd...)
 
-	linkOrderOnly = append(linkOrderOnly, deps.linkObjects...)
+	orderOnly = append(orderOnly, deps.SharedLibs...)
 
 	if len(deps.SrcDeps) > 0 {
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
@@ -353,14 +344,29 @@
 		implicits = append(implicits, outputs.Paths()...)
 	}
 
+	envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
+
+	if ctx.RustModule().compiler.CargoEnvCompat() {
+		if _, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
+			envVars = append(envVars, "CARGO_BIN_NAME="+strings.TrimSuffix(outputFile.Base(), outputFile.Ext()))
+		}
+		envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
+		pkgVersion := ctx.RustModule().compiler.CargoPkgVersion()
+		if pkgVersion != "" {
+			envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
+		}
+	}
+
 	if flags.Clippy {
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        clippyDriver,
-			Description: "clippy " + main.Rel(),
-			Output:      clippyFile,
-			Inputs:      inputs,
-			Implicits:   implicits,
+			Rule:            clippyDriver,
+			Description:     "clippy " + main.Rel(),
+			Output:          clippyFile,
+			ImplicitOutputs: nil,
+			Inputs:          inputs,
+			Implicits:       implicits,
+			OrderOnly:       orderOnly,
 			Args: map[string]string{
 				"rustcFlags":  strings.Join(rustcFlags, " "),
 				"libFlags":    strings.Join(libFlags, " "),
@@ -372,49 +378,24 @@
 		implicits = append(implicits, clippyFile)
 	}
 
-	rustcOutputFile := outputFile
-	var rustcImplicitOutputs android.WritablePaths
-	usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
-	if usesLinker {
-		rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp")
-		rustcImplicitOutputs = android.WritablePaths{
-			android.PathForModuleOut(ctx, rustcOutputFile.Base()+".whole.a"),
-			android.PathForModuleOut(ctx, rustcOutputFile.Base()+".a"),
-		}
-
-	}
-
 	ctx.Build(pctx, android.BuildParams{
-		Rule:            rustc,
-		Description:     "rustc " + main.Rel(),
-		Output:          rustcOutputFile,
-		Inputs:          inputs,
-		Implicits:       implicits,
-		ImplicitOutputs: rustcImplicitOutputs,
+		Rule:        rustc,
+		Description: "rustc " + main.Rel(),
+		Output:      outputFile,
+		Inputs:      inputs,
+		Implicits:   implicits,
+		OrderOnly:   orderOnly,
 		Args: map[string]string{
-			"rustcFlags": strings.Join(rustcFlags, " "),
-			"libFlags":   strings.Join(libFlags, " "),
-			"envVars":    strings.Join(envVars, " "),
+			"rustcFlags":     strings.Join(rustcFlags, " "),
+			"earlyLinkFlags": earlyLinkFlags,
+			"linkFlags":      strings.Join(linkFlags, " "),
+			"libFlags":       strings.Join(libFlags, " "),
+			"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
+			"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
+			"envVars":        strings.Join(envVars, " "),
 		},
 	})
 
-	if usesLinker {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:        rustLink,
-			Description: "rustLink " + main.Rel(),
-			Output:      outputFile,
-			Inputs:      android.Paths{rustcOutputFile},
-			Implicits:   linkImplicits,
-			OrderOnly:   linkOrderOnly,
-			Args: map[string]string{
-				"earlyLinkFlags": earlyLinkFlags,
-				"linkFlags":      strings.Join(linkFlags, " "),
-				"crtBegin":       strings.Join(deps.CrtBegin.Strings(), " "),
-				"crtEnd":         strings.Join(deps.CrtEnd.Strings(), " "),
-			},
-		})
-	}
-
 	if flags.EmitXrefs {
 		kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
 		ctx.Build(pctx, android.BuildParams{
@@ -423,9 +404,13 @@
 			Output:      kytheFile,
 			Inputs:      inputs,
 			Implicits:   implicits,
+			OrderOnly:   orderOnly,
 			Args: map[string]string{
 				"rustcFlags": strings.Join(rustcFlags, " "),
+				"linkFlags":  strings.Join(linkFlags, " "),
 				"libFlags":   strings.Join(libFlags, " "),
+				"crtBegin":   strings.Join(deps.CrtBegin.Strings(), " "),
+				"crtEnd":     strings.Join(deps.CrtEnd.Strings(), " "),
 				"envVars":    strings.Join(envVars, " "),
 			},
 		})
diff --git a/rust/builder_test.go b/rust/builder_test.go
index 1fd675f..639f6d4 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -76,9 +76,6 @@
 			expectedFiles: []string{
 				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so",
 				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.rsp",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.rsp.a",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.rsp.whole.a",
 				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/libfizz_buzz.dylib.so",
 				"out/soong/target/product/test_device/system/lib64/libfizz_buzz.dylib.so",
 				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/meta_lic",
@@ -112,9 +109,6 @@
 			expectedFiles: []string{
 				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz",
 				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.rsp",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.rsp.a",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.rsp.whole.a",
 				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz",
 				"out/soong/target/product/test_device/system/bin/fizz_buzz",
 				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic",
@@ -138,9 +132,6 @@
 			expectedFiles: []string{
 				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so",
 				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.rsp",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.rsp.a",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.rsp.whole.a",
 				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so",
 				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so.toc",
 				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/meta_lic",
diff --git a/rust/compiler.go b/rust/compiler.go
index d6c52e8..b3f574d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -327,10 +327,15 @@
 		flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
 	}
 
-	if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl && !ctx.Windows() {
-		// Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device
-		// builds. This is irrelevant for the Windows target as these are Posix specific.
+	if ctx.Os() == android.Linux {
+		// Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
+		// the default behavior of device builds.
+		flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
+	} else if ctx.Os() == android.Darwin {
+		// Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
+		// behavior of device builds.
 		flags.LinkFlags = append(flags.LinkFlags,
+			"-lc",
 			"-ldl",
 			"-lpthread",
 			"-lm",
diff --git a/rust/config/global.go b/rust/config/global.go
index f397ce9..c37ac4e 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -52,11 +52,22 @@
 		"-C force-unwind-tables=yes",
 		// Use v0 mangling to distinguish from C++ symbols
 		"-C symbol-mangling-version=v0",
-		"--color always",
+		// This flag requires to have no space so that when it's exported to bazel
+		// it can be removed. See aosp/2768339
+		"--color=always",
 		"-Zdylib-lto",
 		"-Z link-native-libraries=no",
 	}
 
+	LinuxHostGlobalLinkFlags = []string{
+		"-lc",
+		"-lrt",
+		"-ldl",
+		"-lpthread",
+		"-lm",
+		"-lgcc_s",
+	}
+
 	deviceGlobalRustFlags = []string{
 		"-C panic=abort",
 		// Generate additional debug info for AutoFDO
@@ -101,6 +112,8 @@
 	pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
 
 	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
+	exportedVars.ExportStringListStaticVariable("GLOBAL_RUSTC_FLAGS", GlobalRustFlags)
+	exportedVars.ExportStringListStaticVariable("LINUX_HOST_GLOBAL_LINK_FLAGS", LinuxHostGlobalLinkFlags)
 }
 
 func HostPrebuiltTag(config android.Config) string {
diff --git a/rust/coverage.go b/rust/coverage.go
index 5216d60..bc6504d 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -65,7 +65,7 @@
 			"-C instrument-coverage", "-g")
 		flags.LinkFlags = append(flags.LinkFlags,
 			profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
-		deps.LibDeps = append(deps.LibDeps, coverage.OutputFile().Path())
+		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
 
 		// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
 		if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 64077cf..0f599d7 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,10 +55,6 @@
 	libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
-	libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustLink")
-	libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustLink")
-	fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustLink")
-	buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustLink")
 
 	rustcCoverageFlags := []string{"-C instrument-coverage", " -g "}
 	for _, flag := range rustcCoverageFlags {
@@ -84,17 +80,17 @@
 		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"])
+		if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
 		}
-		if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"])
+		if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
 		}
-		if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"])
+		if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
 		}
-		if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"])
+		if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
 		}
 	}
 
@@ -107,7 +103,7 @@
 			srcs: ["foo.rs"],
 		}`)
 
-	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink")
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
 	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
 		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
diff --git a/rust/library.go b/rust/library.go
index f4a2b54..c598473 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -525,7 +525,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
-	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -548,7 +548,6 @@
 	if library.rlib() || library.dylib() {
 		library.flagExporter.exportLinkDirs(deps.linkDirs...)
 		library.flagExporter.exportLinkObjects(deps.linkObjects...)
-		library.flagExporter.exportLibDeps(deps.LibDeps...)
 	}
 
 	if library.static() || library.shared() {
diff --git a/rust/library_test.go b/rust/library_test.go
index 30ef333..e03074d 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -148,7 +148,7 @@
 
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
 
-	libfooOutput := libfoo.Rule("rustLink")
+	libfooOutput := libfoo.Rule("rustc")
 	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
 		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
 			libfooOutput.Args["linkFlags"])
diff --git a/rust/rust.go b/rust/rust.go
index 49a7ff3..ba63613 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -447,12 +447,13 @@
 }
 
 type PathDeps struct {
-	DyLibs          RustLibraries
-	RLibs           RustLibraries
-	LibDeps         android.Paths
-	WholeStaticLibs android.Paths
-	ProcMacros      RustLibraries
-	AfdoProfiles    android.Paths
+	DyLibs        RustLibraries
+	RLibs         RustLibraries
+	SharedLibs    android.Paths
+	SharedLibDeps android.Paths
+	StaticLibs    android.Paths
+	ProcMacros    RustLibraries
+	AfdoProfiles  android.Paths
 
 	// depFlags and depLinkFlags are rustc and linker (clang) flags.
 	depFlags     []string
@@ -461,7 +462,7 @@
 	// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
 	// Both of these are exported and propagate to dependencies.
 	linkDirs    []string
-	linkObjects android.Paths
+	linkObjects []string
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
@@ -524,7 +525,7 @@
 
 type exportedFlagsProducer interface {
 	exportLinkDirs(...string)
-	exportLinkObjects(...android.Path)
+	exportLinkObjects(...string)
 }
 
 type xref interface {
@@ -533,27 +534,21 @@
 
 type flagExporter struct {
 	linkDirs    []string
-	linkObjects android.Paths
-	libDeps     android.Paths
+	linkObjects []string
 }
 
 func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
 	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
 
-func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
-	flagExporter.linkObjects = android.FirstUniquePaths(append(flagExporter.linkObjects, flags...))
-}
-
-func (flagExporter *flagExporter) exportLibDeps(paths ...android.Path) {
-	flagExporter.libDeps = android.FirstUniquePaths(append(flagExporter.libDeps, paths...))
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
 }
 
 func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
 	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
 		LinkDirs:    flagExporter.linkDirs,
 		LinkObjects: flagExporter.linkObjects,
-		LibDeps:     flagExporter.libDeps,
 	})
 }
 
@@ -566,8 +561,7 @@
 type FlagExporterInfo struct {
 	Flags       []string
 	LinkDirs    []string // TODO: this should be android.Paths
-	LinkObjects android.Paths
-	LibDeps     android.Paths
+	LinkObjects []string // TODO: this should be android.Paths
 }
 
 var FlagExporterInfoProvider = blueprint.NewProvider(FlagExporterInfo{})
@@ -1319,7 +1313,6 @@
 				depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
 				depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
 				depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
-				depPaths.LibDeps = append(depPaths.LibDeps, exportedInfo.LibDeps...)
 			}
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -1375,7 +1368,6 @@
 						depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...)
 					} else if libName, ok := libNameFromFilePath(linkObject.Path()); ok {
 						depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName)
-						depPaths.WholeStaticLibs = append(depPaths.WholeStaticLibs, linkObject.Path())
 					} else {
 						ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName())
 					}
@@ -1383,7 +1375,7 @@
 
 				// Add this to linkObjects to pass the library directly to the linker as well. This propagates
 				// to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant.
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 
 				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
@@ -1417,7 +1409,7 @@
 				linkPath = linkPathFromFilePath(linkObject.Path())
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
-				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
+				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
 				depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...)
@@ -1443,9 +1435,7 @@
 			// Make sure these dependencies are propagated
 			if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
 				lib.exportLinkDirs(linkPath)
-				if linkObject.Valid() {
-					lib.exportLinkObjects(linkObject.Path())
-				}
+				lib.exportLinkObjects(linkObject.String())
 			}
 		} else {
 			switch {
@@ -1479,16 +1469,19 @@
 		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
 	}
 
-	var libDepFiles android.Paths
+	var staticLibDepFiles android.Paths
 	for _, dep := range directStaticLibDeps {
-		libDepFiles = append(libDepFiles, dep.OutputFile().Path())
+		staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path())
 	}
 
+	var sharedLibFiles android.Paths
+	var sharedLibDepFiles android.Paths
 	for _, dep := range directSharedLibDeps {
+		sharedLibFiles = append(sharedLibFiles, dep.SharedLibrary)
 		if dep.TableOfContents.Valid() {
-			libDepFiles = append(libDepFiles, dep.TableOfContents.Path())
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.TableOfContents.Path())
 		} else {
-			libDepFiles = append(libDepFiles, dep.SharedLibrary)
+			sharedLibDepFiles = append(sharedLibDepFiles, dep.SharedLibrary)
 		}
 	}
 
@@ -1504,13 +1497,15 @@
 
 	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
 	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
-	depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
+	depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibFiles...)
+	depPaths.SharedLibDeps = append(depPaths.SharedLibDeps, sharedLibDepFiles...)
+	depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
 	depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
 	depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
 
 	// Dedup exported flags from dependencies
 	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
-	depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
+	depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
 	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
 	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 835114c..d609c2f 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -40,7 +40,6 @@
 	PrepareForTestWithRustIncludeVndk,
 	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
 		variables.DeviceVndkVersion = StringPtr("current")
-		variables.ProductVndkVersion = StringPtr("current")
 		variables.Platform_vndk_version = StringPtr("29")
 	}),
 )
@@ -105,7 +104,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr(device_version)
-				variables.ProductVndkVersion = StringPtr(product_version)
 				variables.Platform_vndk_version = StringPtr(vndk_version)
 			},
 		),
@@ -173,7 +171,6 @@
 		android.FixtureModifyProductVariables(
 			func(variables android.FixtureProductVariables) {
 				variables.DeviceVndkVersion = StringPtr("current")
-				variables.ProductVndkVersion = StringPtr("current")
 				variables.Platform_vndk_version = StringPtr("VER")
 			},
 		),
@@ -256,7 +253,6 @@
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 	rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
-	rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustLink")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
 	if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) {
@@ -279,16 +275,16 @@
 		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
-		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
+	if !strings.Contains(rustc.Args["linkFlags"], "cc_stubs_dep.so") {
+		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustc.Args["linkFlags"])
 	}
 
-	if !android.SuffixInList(rustLink.OrderOnly.Strings(), "cc_stubs_dep.so") {
-		t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustLink.OrderOnly.Strings())
+	if !android.SuffixInList(rustc.OrderOnly.Strings(), "cc_stubs_dep.so") {
+		t.Errorf("shared cc dep not being passed as order-only to rustc %#v", rustc.OrderOnly.Strings())
 	}
 
-	if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
-		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustLink.Implicits.Strings())
+	if !android.SuffixInList(rustc.Implicits.Strings(), "cc_stubs_dep.so.toc") {
+		t.Errorf("shared cc dep TOC not being passed as implicit to rustc %#v", rustc.Implicits.Strings())
 	}
 }
 
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
index 43e95f4..d6a14b2 100644
--- a/rust/sanitize_test.go
+++ b/rust/sanitize_test.go
@@ -35,7 +35,7 @@
 	note_sync := "note_memtag_heap_sync"
 
 	found := None
-	implicits := m.Rule("rustLink").Implicits
+	implicits := m.Rule("rustc").Implicits
 	for _, lib := range implicits {
 		if strings.Contains(lib.Rel(), note_async) {
 			found = Async
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 1e7e7d3..4f45799 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -1051,7 +1051,7 @@
 	ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31")
 
 	// libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"]
+	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").Args["linkFlags"]
 	for _, input := range [][]string{
 		[]string{sharedVariant, "libvndk.vndk.30.arm64"},
 		[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
@@ -1119,7 +1119,7 @@
 		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName)
 	}
 
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").Args["linkFlags"]
+	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").Args["linkFlags"]
 	libVndkStaticOutputPaths := cc.GetOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.30.arm64"})
 	if !strings.Contains(binWithoutSnapshotLdFlags, libVndkStaticOutputPaths[0].String()) {
 		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index c6aa3d0..c6e6e30 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -62,8 +62,8 @@
     if args.source:
         for input in args.source.split(':'):
             pb.MergeFrom(LoadJsonMessage(input))
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Print(args):
@@ -90,8 +90,8 @@
     for item in installed_libraries:
         if item not in getattr(pb, 'provideLibs'):
             getattr(pb, 'provideLibs').append(item)
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Append(args):
@@ -106,8 +106,8 @@
     else:
         setattr(pb, args.key, args.value)
 
-    with open(args.output, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
+
 
 
 def Merge(args):
@@ -116,8 +116,7 @@
         with open(other, 'rb') as f:
             pb.MergeFromString(f.read())
 
-    with open(args.out, 'wb') as f:
-        f.write(pb.SerializeToString())
+    ValidateAndWriteAsPbFile(pb, args.output)
 
 
 def Validate(args):
@@ -151,6 +150,29 @@
         sys.exit(f'Unknown type: {args.type}')
 
 
+def ValidateAndWriteAsPbFile(pb, output_path):
+    ValidateConfiguration(pb)
+    with open(output_path, 'wb') as f:
+        f.write(pb.SerializeToString())
+
+
+def ValidateConfiguration(pb):
+    """
+    Validate if the configuration is valid to be used as linker configuration
+    """
+
+    # Validate if provideLibs and requireLibs have common module
+    provideLibs = set(getattr(pb, 'provideLibs'))
+    requireLibs = set(getattr(pb, 'requireLibs'))
+
+    intersectLibs = provideLibs.intersection(requireLibs)
+
+    if intersectLibs:
+        for lib in intersectLibs:
+            print(f'{lib} exists both in requireLibs and provideLibs', file=sys.stderr)
+        sys.exit(1)
+
+
 def GetArgParser():
     parser = argparse.ArgumentParser()
     subparsers = parser.add_subparsers()
diff --git a/scripts/mkcratersp.py b/scripts/mkcratersp.py
deleted file mode 100755
index 6ef01eb..0000000
--- a/scripts/mkcratersp.py
+++ /dev/null
@@ -1,85 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2023 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-"""
-This script is used as a replacement for the Rust linker. It converts a linker
-command line into a rspfile that can be used during the link phase.
-"""
-
-import os
-import shutil
-import subprocess
-import sys
-
-def create_archive(out, objects, archives):
-  mricmd = f'create {out}\n'
-  for o in objects:
-    mricmd += f'addmod {o}\n'
-  for a in archives:
-    mricmd += f'addlib {a}\n'
-  mricmd += 'save\nend\n'
-  subprocess.run([os.getenv('AR'), '-M'], encoding='utf-8', input=mricmd, check=True)
-
-objects = []
-archives = []
-linkdirs = []
-libs = []
-temp_archives = []
-version_script = None
-
-for i, arg in enumerate(sys.argv):
-  if arg == '-o':
-    out = sys.argv[i+1]
-  if arg == '-L':
-    linkdirs.append(sys.argv[i+1])
-  if arg.startswith('-l') or arg == '-shared':
-    libs.append(arg)
-  if os.getenv('ANDROID_RUST_DARWIN') and (arg == '-dylib' or arg == '-dynamiclib'):
-    libs.append(arg)
-  if arg.startswith('-Wl,--version-script='):
-    version_script = arg[21:]
-  if arg[0] == '-':
-    continue
-  if arg.endswith('.o') or arg.endswith('.rmeta'):
-    objects.append(arg)
-  if arg.endswith('.rlib'):
-    if arg.startswith(os.getenv('TMPDIR')):
-      temp_archives.append(arg)
-    else:
-      archives.append(arg)
-
-create_archive(f'{out}.whole.a', objects, [])
-create_archive(f'{out}.a', [], temp_archives)
-
-with open(out, 'w') as f:
-  if os.getenv("ANDROID_RUST_DARWIN"):
-    print(f'-force_load', file=f)
-    print(f'{out}.whole.a', file=f)
-  else:
-    print(f'-Wl,--whole-archive', file=f)
-    print(f'{out}.whole.a', file=f)
-    print(f'-Wl,--no-whole-archive', file=f)
-  print(f'{out}.a', file=f)
-  for a in archives:
-    print(a, file=f)
-  for linkdir in linkdirs:
-    print(f'-L{linkdir}', file=f)
-  for l in libs:
-    print(l, file=f)
-  if version_script:
-    shutil.copyfile(version_script, f'{out}.version_script')
-    print(f'-Wl,--version-script={out}.version_script', file=f)
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 80b86e0..e51fe39 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -42,6 +42,7 @@
 		cc_library_headers {
 			name: "libbase_headers",
 			vendor_available: true,
+			product_available: true,
 			recovery_available: true,
 		}
 
@@ -250,6 +251,16 @@
 		result.ModuleForTests("libsysprop-odm", variant)
 	}
 
+	// product variant of vendor-owned sysprop_library
+	for _, variant := range []string{
+		"android_product.29_arm_armv7-a-neon_shared",
+		"android_product.29_arm_armv7-a-neon_static",
+		"android_product.29_arm64_armv8-a_shared",
+		"android_product.29_arm64_armv8-a_static",
+	} {
+		result.ModuleForTests("libsysprop-vendor-on-product", variant)
+	}
+
 	for _, variant := range []string{
 		"android_arm_armv7-a-neon_shared",
 		"android_arm_armv7-a-neon_static",
@@ -259,9 +270,6 @@
 		library := result.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
 		expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
 		android.AssertDeepEquals(t, "apex available property on libsysprop-platform", expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
-
-		// product variant of vendor-owned sysprop_library
-		result.ModuleForTests("libsysprop-vendor-on-product", variant)
 	}
 
 	result.ModuleForTests("sysprop-platform", "android_common")
@@ -272,15 +280,15 @@
 	// Check for exported includes
 	coreVariant := "android_arm64_armv8-a_static"
 	vendorVariant := "android_vendor.29_arm64_armv8-a_static"
+	productVariant := "android_product.29_arm64_armv8-a_static"
 
 	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/include"
-	platformPublicCorePath := "libsysprop-platform/android_arm64_armv8-a_static/gen/sysprop/public/include"
 	platformPublicVendorPath := "libsysprop-platform/android_vendor.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
-	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	platformOnProductPath := "libsysprop-platform-on-product/android_product.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	vendorInternalPath := "libsysprop-vendor/android_vendor.29_arm64_armv8-a_static/gen/sysprop/include"
-	vendorPublicPath := "libsysprop-vendor-on-product/android_arm64_armv8-a_static/gen/sysprop/public/include"
+	vendorOnProductPath := "libsysprop-vendor-on-product/android_product.29_arm64_armv8-a_static/gen/sysprop/public/include"
 
 	platformClient := result.ModuleForTests("cc-client-platform", coreVariant)
 	platformFlags := platformClient.Rule("cc").Args["cFlags"]
@@ -294,14 +302,14 @@
 	// platform-static should use platform's internal header
 	android.AssertStringDoesContain(t, "flags for platform-static", platformStaticFlags, platformInternalPath)
 
-	productClient := result.ModuleForTests("cc-client-product", coreVariant)
+	productClient := result.ModuleForTests("cc-client-product", productVariant)
 	productFlags := productClient.Rule("cc").Args["cFlags"]
 
 	// Product should use platform's and vendor's public headers
 	if !strings.Contains(productFlags, platformOnProductPath) ||
-		!strings.Contains(productFlags, vendorPublicPath) {
+		!strings.Contains(productFlags, vendorOnProductPath) {
 		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
-			platformPublicCorePath, vendorPublicPath, productFlags)
+			platformOnProductPath, vendorOnProductPath, productFlags)
 	}
 
 	vendorClient := result.ModuleForTests("cc-client-vendor", vendorVariant)
diff --git a/tests/lib.sh b/tests/lib.sh
index 0766d85..fb3b374 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -8,6 +8,11 @@
 
 REAL_TOP="$(readlink -f "$(dirname "$0")"/../../..)"
 
+function make_mock_top {
+  mock=$(mktemp -t -d st.XXXXX)
+  echo "$mock"
+}
+
 if [[ -n "$HARDWIRED_MOCK_TOP" ]]; then
   MOCK_TOP="$HARDWIRED_MOCK_TOP"
 else
@@ -158,6 +163,7 @@
   symlink_directory external/bazelbuild-rules_python
   symlink_directory external/bazelbuild-rules_java
   symlink_directory external/bazelbuild-rules_rust
+  symlink_directory external/bazelbuild-rules_testing
   symlink_directory external/rust/crates/tinyjson
 
   symlink_file WORKSPACE
@@ -197,3 +203,11 @@
     info "Completed test case \e[96;1m$f\e[0m"
   done
 }
+
+function move_mock_top {
+  MOCK_TOP2=$(make_mock_top)
+  rm -rf $MOCK_TOP2
+  mv $MOCK_TOP $MOCK_TOP2
+  MOCK_TOP=$MOCK_TOP2
+  trap cleanup_mock_top EXIT
+}
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 6b9ff8b..223baa4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -23,4 +23,4 @@
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
 
 "$TOP/build/bazel/ci/b_test.sh"
-
+"$TOP/build/soong/tests/symlinks_path_test.sh"
diff --git a/tests/symlinks_path_test.sh b/tests/symlinks_path_test.sh
new file mode 100755
index 0000000..ed42911
--- /dev/null
+++ b/tests/symlinks_path_test.sh
@@ -0,0 +1,51 @@
+#!/bin/bash -eu
+
+set -o pipefail
+
+# Test that relative symlinks work by recreating the bug in b/259191764
+# In some cases, developers prefer to move their checkouts. This causes
+# issues in that symlinked files (namely, the bazel wrapper script)
+# cannot be found. As such, we implemented relative symlinks so that a
+# moved checkout doesn't need a full clean before rebuilding.
+# The bazel output base will still need to be removed, as Starlark
+# doesn't seem to support relative symlinks yet.
+
+source "$(dirname "$0")/lib.sh"
+
+function check_link_has_mock_top_prefix {
+  input_link=$1
+  link_target=`readlink $input_link`
+  if [[ $link_target != "$MOCK_TOP"* ]]; then
+    echo "Symlink for file $input_link -> $link_target doesn't start with $MOCK_TOP"
+    exit 1
+  fi
+}
+
+function test_symlinks_updated_when_top_dir_changed {
+  setup
+
+  mkdir -p a
+  touch a/g.txt
+  cat > a/Android.bp <<'EOF'
+filegroup {
+    name: "g",
+    srcs: ["g.txt"],
+    bazel_module: {bp2build_available: true},
+}
+EOF
+  # A directory under $MOCK_TOP
+  outdir=out2
+
+  # Modify OUT_DIR in a subshell so it doesn't affect the top level one.
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+
+  g_txt="out2/soong/workspace/a/g.txt"
+  check_link_has_mock_top_prefix "$g_txt"
+
+  move_mock_top
+
+  (export OUT_DIR=$MOCK_TOP/$outdir; run_soong bp2build && run_bazel build --config=bp2build --config=ci //a:g)
+  check_link_has_mock_top_prefix "$g_txt"
+}
+
+scan_and_run_tests
\ No newline at end of file
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 44c20a0..ac9bf3a 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -16,10 +16,13 @@
 
 import (
 	"fmt"
+	"io/fs"
 	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
+	"sync"
+	"sync/atomic"
 
 	"android/soong/bazel"
 	"android/soong/ui/metrics"
@@ -50,6 +53,13 @@
 	bootstrapEpoch = 1
 )
 
+var (
+	// Used during parallel update of symlinks in out directory to reflect new
+	// TOP dir.
+	symlinkWg            sync.WaitGroup
+	numFound, numUpdated uint32
+)
+
 func writeEnvironmentFile(_ Context, envFile string, envDeps map[string]string) error {
 	data, err := shared.EnvFileContents(envDeps)
 	if err != nil {
@@ -465,10 +475,118 @@
 	}
 }
 
+func updateSymlinks(ctx Context, dir, prevCWD, cwd string) error {
+	defer symlinkWg.Done()
+
+	visit := func(path string, d fs.DirEntry, err error) error {
+		if d.IsDir() && path != dir {
+			symlinkWg.Add(1)
+			go updateSymlinks(ctx, path, prevCWD, cwd)
+			return filepath.SkipDir
+		}
+		f, err := d.Info()
+		if err != nil {
+			return err
+		}
+		// If the file is not a symlink, we don't have to update it.
+		if f.Mode()&os.ModeSymlink != os.ModeSymlink {
+			return nil
+		}
+
+		atomic.AddUint32(&numFound, 1)
+		target, err := os.Readlink(path)
+		if err != nil {
+			return err
+		}
+		if strings.HasPrefix(target, prevCWD) &&
+			(len(target) == len(prevCWD) || target[len(prevCWD)] == '/') {
+			target = filepath.Join(cwd, target[len(prevCWD):])
+			if err := os.Remove(path); err != nil {
+				return err
+			}
+			if err := os.Symlink(target, path); err != nil {
+				return err
+			}
+			atomic.AddUint32(&numUpdated, 1)
+		}
+		return nil
+	}
+
+	if err := filepath.WalkDir(dir, visit); err != nil {
+		return err
+	}
+	return nil
+}
+
+func fixOutDirSymlinks(ctx Context, config Config, outDir string) error {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return err
+	}
+
+	// Record the .top as the very last thing in the function.
+	tf := filepath.Join(outDir, ".top")
+	defer func() {
+		if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil {
+			fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err))
+		}
+	}()
+
+	// Find the previous working directory if it was recorded.
+	var prevCWD string
+	pcwd, err := os.ReadFile(tf)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No previous working directory recorded, nothing to do.
+			return nil
+		}
+		return err
+	}
+	prevCWD = strings.Trim(string(pcwd), "\n")
+
+	if prevCWD == cwd {
+		// We are in the same source dir, nothing to update.
+		return nil
+	}
+
+	symlinkWg.Add(1)
+	if err := updateSymlinks(ctx, outDir, prevCWD, cwd); err != nil {
+		return err
+	}
+	symlinkWg.Wait()
+	ctx.Println(fmt.Sprintf("Updated %d/%d symlinks in dir %v", numUpdated, numFound, outDir))
+	return nil
+}
+
+func migrateOutputSymlinks(ctx Context, config Config) error {
+	// Figure out the real out directory ("out" could be a symlink).
+	outDir := config.OutDir()
+	s, err := os.Lstat(outDir)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// No out dir exists, no symlinks to migrate.
+			return nil
+		}
+		return err
+	}
+	if s.Mode()&os.ModeSymlink == os.ModeSymlink {
+		target, err := filepath.EvalSymlinks(outDir)
+		if err != nil {
+			return err
+		}
+		outDir = target
+	}
+	return fixOutDirSymlinks(ctx, config, outDir)
+}
+
 func runSoong(ctx Context, config Config) {
 	ctx.BeginTrace(metrics.RunSoong, "soong")
 	defer ctx.EndTrace()
 
+	if err := migrateOutputSymlinks(ctx, config); err != nil {
+		ctx.Fatalf("failed to migrate output directory to current TOP dir: %v", err)
+	}
+
 	// We have two environment files: .available is the one with every variable,
 	// .used with the ones that were actually used. The latter is used to
 	// determine whether Soong needs to be re-run since why re-run it if only