Merge "Emit a system image target for the current product" into main
diff --git a/aconfig/rust_aconfig_library_test.go b/aconfig/rust_aconfig_library_test.go
index 90b09c8..17385c3 100644
--- a/aconfig/rust_aconfig_library_test.go
+++ b/aconfig/rust_aconfig_library_test.go
@@ -50,11 +50,11 @@
 	}
 
 	for _, variant := range variants {
-		android.AssertStringListContains(
+		android.AssertStringEquals(
 			t,
 			"dylib variant builds from generated rust code",
-			variant.Rule("rustc").Implicits.RelativeToTop().Strings(),
 			"out/soong/.intermediates/libmy_rust_aconfig_library/android_arm64_armv8-a_source/gen/src/lib.rs",
+			variant.Rule("rustc").Inputs[0].RelativeToTop().String(),
 		)
 	}
 }
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index ca5f8e9..deb44a2 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -755,6 +755,7 @@
 		//system/core/fs_mgr
 		"libfs_mgr",
 
+		"libcodec2_aidl",
 		"libcodec2_hidl@1.0",
 		"libcodec2_hidl@1.1",
 		"libcodec2_hidl@1.2",
@@ -947,6 +948,7 @@
 		"gson",
 		"GsonBuildConfig.java",
 		"gson_version_generator",
+		"lab-resource-grpc",
 	}
 
 	Bp2buildModuleTypeAlwaysConvertList = []string{
diff --git a/android/api_domain.go b/android/api_domain.go
index 587ceae..0603c70 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -107,24 +107,3 @@
 	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
 	return bazel.MakeLabelListAttribute(bazelLabels)
 }
-
-type bazelApiDomainAttributes struct {
-	Cc_api_contributions   bazel.LabelListAttribute
-	Java_api_contributions bazel.LabelListAttribute
-}
-
-var _ ApiProvider = (*apiDomain)(nil)
-
-func (a *apiDomain) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "api_domain",
-		Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
-	}
-	attrs := &bazelApiDomainAttributes{
-		Cc_api_contributions:   contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
-		Java_api_contributions: contributionBazelAttributes(ctx, a.properties.Java_api_contributions),
-	}
-	ctx.CreateBazelTargetModule(props, CommonAttributes{
-		Name: ctx.ModuleName(),
-	}, attrs)
-}
diff --git a/android/bazel.go b/android/bazel.go
index 8634dab..4516396 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -600,17 +600,10 @@
 }
 
 func registerBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("bp2build_conversion", bp2buildConversionMutator).Parallel()
+	ctx.BottomUp("bp2build_conversion", bp2buildConversionMutator).Parallel()
 }
 
-func bp2buildConversionMutator(ctx TopDownMutatorContext) {
-	if ctx.Config().HasBazelBuildTargetInSource(ctx) {
-		// Defer to the BUILD target. Generating an additional target would
-		// cause a BUILD file conflict.
-		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, "")
-		return
-	}
-
+func bp2buildConversionMutator(ctx BottomUpMutatorContext) {
 	bModule, ok := ctx.Module().(Bazelable)
 	if !ok {
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED, "")
@@ -634,21 +627,23 @@
 		ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_UNSUPPORTED, "")
 		return
 	}
+	if ctx.Module().base().GetUnconvertedReason() != nil {
+		return
+	}
+
 	bModule.ConvertWithBp2build(ctx)
 
-	if !ctx.Module().base().IsConvertedByBp2build() && ctx.Module().base().GetUnconvertedReason() == nil {
+	if len(ctx.Module().base().Bp2buildTargets()) == 0 && ctx.Module().base().GetUnconvertedReason() == nil {
 		panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", ctx.ModuleName()))
 	}
-}
 
-func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
-	ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
-}
-
-// Generate API contribution targets if the Soong module provides APIs
-func convertWithApiBp2build(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(ApiProvider); ok {
-		m.ConvertWithApiBp2build(ctx)
+	for _, targetInfo := range ctx.Module().base().Bp2buildTargets() {
+		if ctx.Config().HasBazelBuildTargetInSource(targetInfo.TargetPackage(), targetInfo.TargetName()) {
+			// Defer to the BUILD target. Generating an additional target would
+			// cause a BUILD file conflict.
+			ctx.MarkBp2buildUnconvertible(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE, targetInfo.TargetName())
+			return
+		}
 	}
 }
 
diff --git a/android/config.go b/android/config.go
index df282ec..f9d616d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -2022,10 +2022,9 @@
 	}
 }
 
-func (c *config) HasBazelBuildTargetInSource(ctx BaseModuleContext) bool {
-	moduleName := ctx.Module().Name()
-	for _, buildTarget := range c.bazelTargetsByDir[ctx.ModuleDir()] {
-		if moduleName == buildTarget {
+func (c *config) HasBazelBuildTargetInSource(dir string, target string) bool {
+	for _, existingTarget := range c.bazelTargetsByDir[dir] {
+		if target == existingTarget {
 			return true
 		}
 	}
diff --git a/android/depset_generic.go b/android/depset_generic.go
index 9f07596..45c1937 100644
--- a/android/depset_generic.go
+++ b/android/depset_generic.go
@@ -95,12 +95,6 @@
 	}
 }
 
-// AddDirectToDepSet returns a new DepSet with additional elements added to its direct set.
-// The transitive sets remain untouched.
-func AddDirectToDepSet[T depSettableType](d *DepSet[T], direct ...T) *DepSet[T] {
-	return NewDepSet[T](d.order, Concat(d.direct, direct), d.transitive)
-}
-
 // DepSetBuilder is used to create an immutable DepSet.
 type DepSetBuilder[T depSettableType] struct {
 	order      DepSetOrder
@@ -194,14 +188,3 @@
 	}
 	return list
 }
-
-// ToListDirect returns the direct elements of a DepSet flattened to a list.
-func (d *DepSet[T]) ToListDirect() []T {
-	if d == nil {
-		return nil
-	}
-	list := make([]T, len(d.direct))
-	copy(list, d.direct)
-	list = firstUniqueInPlace(list)
-	return list
-}
diff --git a/android/filegroup.go b/android/filegroup.go
index a4bbcae..5a8c4b9 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -86,12 +86,6 @@
 	Strip_import_prefix *string
 }
 
-// api srcs can be contained in filegroups.
-// this should be generated in api_bp2build workspace as well.
-func (fg *fileGroup) ConvertWithApiBp2build(ctx TopDownMutatorContext) {
-	fg.ConvertWithBp2build(ctx)
-}
-
 // ConvertWithBp2build performs bp2build conversion of filegroup
 func (fg *fileGroup) ConvertWithBp2build(ctx Bp2buildMutatorContext) {
 	srcs := bazel.MakeLabelListAttribute(
diff --git a/android/module.go b/android/module.go
index f48af4a..74b8cb8 100644
--- a/android/module.go
+++ b/android/module.go
@@ -565,8 +565,8 @@
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
 
-	// IsConvertedByBp2build returns whether this module was converted via bp2build
-	IsConvertedByBp2build() bool
+	// If this module should not have bazel BUILD definitions generated by bp2build,
+	// GetUnconvertedReason returns a reason this is the case.
 	GetUnconvertedReason() *UnconvertedReason
 
 	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module
@@ -1272,7 +1272,7 @@
 	m.base().commonProperties.CreateCommonOSVariant = true
 }
 
-func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *topDownMutatorContext,
+func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *bottomUpMutatorContext,
 	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes {
 
 	mod := ctx.Module().base()
@@ -1430,7 +1430,7 @@
 // If compile_mulitilib is set to
 // 1. 32: Add an incompatibility constraint for non-32 arches
 // 1. 64: Add an incompatibility constraint for non-64 arches
-func addCompatibilityConstraintForCompileMultilib(ctx *topDownMutatorContext, enabled *bazel.LabelListAttribute) {
+func addCompatibilityConstraintForCompileMultilib(ctx *bottomUpMutatorContext, enabled *bazel.LabelListAttribute) {
 	mod := ctx.Module().base()
 	multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice())
 
@@ -1456,7 +1456,7 @@
 
 // Check product variables for `enabled: true` flag override.
 // Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
+func productVariableConfigEnableAttribute(ctx *bottomUpMutatorContext) bazel.LabelListAttribute {
 	result := bazel.LabelListAttribute{}
 	productVariableProps, errs := ProductVariableProperties(ctx, ctx.Module())
 	for _, err := range errs {
@@ -1639,35 +1639,16 @@
 }
 
 func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) {
-	reason := m.commonProperties.BazelConversionStatus.UnconvertedReason
-	if reason != nil {
-		panic(fmt.Errorf("bp2build: internal error trying to convert module '%s' marked unconvertible. Reason type %d: %s",
-			m.Name(),
-			reason.ReasonType,
-			reason.Detail))
-	}
 	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info)
 }
 
 func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
-	if len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0 {
-		fmt.Println(m.commonProperties.BazelConversionStatus.Bp2buildInfo)
-		panic(fmt.Errorf("bp2build: internal error trying to mark converted module '%s' as unconvertible. Reason type %d: %s",
-			m.Name(),
-			reasonType,
-			detail))
-	}
 	m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{
 		ReasonType: int(reasonType),
 		Detail:     detail,
 	}
 }
 
-// IsConvertedByBp2build returns whether this module was converted via bp2build.
-func (m *ModuleBase) IsConvertedByBp2build() bool {
-	return len(m.commonProperties.BazelConversionStatus.Bp2buildInfo) > 0
-}
-
 func (m *ModuleBase) GetUnconvertedReason() *UnconvertedReason {
 	return m.commonProperties.BazelConversionStatus.UnconvertedReason
 }
diff --git a/android/mutator.go b/android/mutator.go
index 336f8f7..57ff1e0 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -38,13 +38,6 @@
 	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
 }
 
-// RegisterMutatorsForApiBazelConversion is an alternate registration pipeline for api_bp2build
-// This pipeline restricts generation of Bazel targets to Soong modules that contribute APIs
-func RegisterMutatorsForApiBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
-	bp2buildMutators := append(preArchMutators, registerApiBp2buildConversionMutator)
-	registerMutatorsForBazelConversion(ctx, bp2buildMutators)
-}
-
 func registerMutatorsForBazelConversion(ctx *Context, bp2buildMutators []RegisterMutatorFunc) {
 	mctx := &registerMutatorsContext{
 		bazelConversionMode: true,
@@ -284,7 +277,6 @@
 
 type TopDownMutatorContext interface {
 	BaseMutatorContext
-	Bp2buildMutatorContext
 
 	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
 	// the specified property structs to it as if the properties were set in a blueprint file.
@@ -300,6 +292,7 @@
 
 type BottomUpMutatorContext interface {
 	BaseMutatorContext
+	Bp2buildMutatorContext
 
 	// AddDependency adds a dependency to the given module.  It returns a slice of modules for each
 	// dependency (some entries may be nil).
@@ -711,14 +704,14 @@
 	ctx.BottomUp("deps", depsMutator).Parallel()
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetModule(
+func (t *bottomUpMutatorContext) CreateBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{}) {
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, bazel.BoolAttribute{})
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetModuleWithRestrictions(
+func (t *bottomUpMutatorContext) CreateBazelTargetModuleWithRestrictions(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
@@ -726,7 +719,7 @@
 	t.createBazelTargetModule(bazelProps, commonAttrs, attrs, enabledProperty)
 }
 
-func (t *topDownMutatorContext) MarkBp2buildUnconvertible(
+func (t *bottomUpMutatorContext) MarkBp2buildUnconvertible(
 	reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) {
 	mod := t.Module()
 	mod.base().setBp2buildUnconvertible(reasonType, detail)
@@ -742,7 +735,7 @@
 	Actual *bazel.LabelAttribute
 }
 
-func (t *topDownMutatorContext) CreateBazelTargetAliasInDir(
+func (t *bottomUpMutatorContext) CreateBazelTargetAliasInDir(
 	dir string,
 	name string,
 	actual bazel.Label) {
@@ -763,7 +756,7 @@
 // Returns the directory in which the bazel target will be generated
 // If ca.Dir is not nil, use that
 // Otherwise default to the directory of the soong module
-func dirForBazelTargetGeneration(t *topDownMutatorContext, ca *CommonAttributes) string {
+func dirForBazelTargetGeneration(t *bottomUpMutatorContext, ca *CommonAttributes) string {
 	dir := t.OtherModuleDir(t.Module())
 	if ca.Dir != nil {
 		dir = *ca.Dir
@@ -781,7 +774,7 @@
 	return dir
 }
 
-func (t *topDownMutatorContext) CreateBazelConfigSetting(
+func (t *bottomUpMutatorContext) CreateBazelConfigSetting(
 	csa bazel.ConfigSettingAttributes,
 	ca CommonAttributes,
 	dir string) {
@@ -867,7 +860,7 @@
 	return ConvertApexAvailableToTags(noTestApexes)
 }
 
-func (t *topDownMutatorContext) createBazelTargetModule(
+func (t *bottomUpMutatorContext) createBazelTargetModule(
 	bazelProps bazel.BazelTargetModuleProperties,
 	commonAttrs CommonAttributes,
 	attrs interface{},
diff --git a/android/paths.go b/android/paths.go
index d4b1d6e..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -171,9 +171,6 @@
 	// Base returns the last element of the path
 	Base() string
 
-	// Dir returns a path pointing the directory containing the path
-	Dir() Path
-
 	// Rel returns the portion of the path relative to the directory it was created from.  For
 	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
 	// directory, and OutputPath.Join("foo").Rel() would return "foo".
@@ -1015,12 +1012,6 @@
 	return filepath.Base(p.path)
 }
 
-func (p basePath) Dir() Path {
-	p.path = filepath.Dir(p.path)
-	p.rel = filepath.Dir(p.rel)
-	return p
-}
-
 func (p basePath) Rel() string {
 	if p.rel != "" {
 		return p.rel
@@ -1055,11 +1046,6 @@
 	return p
 }
 
-func (p SourcePath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // safePathForSource is for paths that we expect are safe -- only for use by go
 // code that is embedding ninja variables in paths
 func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
@@ -1262,12 +1248,6 @@
 	return p
 }
 
-func (p OutputPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	p.fullPath = filepath.Dir(p.fullPath)
-	return p
-}
-
 func (p OutputPath) WithoutRel() OutputPath {
 	p.basePath.rel = filepath.Base(p.basePath.path)
 	return p
@@ -1300,11 +1280,6 @@
 	basePath
 }
 
-func (p toolDepPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (t toolDepPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return t
@@ -1488,11 +1463,6 @@
 	OutputPath
 }
 
-func (p ModuleOutPath) Dir() Path {
-	p.OutputPath = p.OutputPath.Dir().(OutputPath)
-	return p
-}
-
 func (p ModuleOutPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1537,11 +1507,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleGenPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleGenPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1581,11 +1546,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleObjPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleObjPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1610,11 +1570,6 @@
 	ModuleOutPath
 }
 
-func (p ModuleResPath) Dir() Path {
-	p.ModuleOutPath = p.ModuleOutPath.Dir().(ModuleOutPath)
-	return p
-}
-
 func (p ModuleResPath) RelativeToTop() Path {
 	p.OutputPath = p.outputPathRelativeToTop()
 	return p
@@ -1651,11 +1606,6 @@
 	makePath bool
 }
 
-func (p InstallPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 // Will panic if called from outside a test environment.
 func ensureTestOnly() {
 	if PrefixInList(os.Args, "-test.") {
@@ -1972,11 +1922,6 @@
 	basePath
 }
 
-func (p PhonyPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p PhonyPath) writablePath() {}
 
 func (p PhonyPath) getSoongOutDir() string {
@@ -2002,11 +1947,6 @@
 	basePath
 }
 
-func (p testPath) Dir() Path {
-	p.basePath = p.basePath.Dir().(basePath)
-	return p
-}
-
 func (p testPath) RelativeToTop() Path {
 	ensureTestOnly()
 	return p
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index c00b22b..aeae20f 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -14,14 +14,10 @@
 
 package android
 
-import (
-	"path/filepath"
-
-	"github.com/google/blueprint"
-)
+import "path/filepath"
 
 func init() {
-	RegisterModuleType("prebuilt_build_tool", NewPrebuiltBuildTool)
+	RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory)
 }
 
 type prebuiltBuildToolProperties struct {
@@ -59,13 +55,6 @@
 	}
 }
 
-type PrebuiltBuildToolInfo struct {
-	Src  Path
-	Deps Paths
-}
-
-var PrebuiltBuildToolInfoProvider = blueprint.NewProvider(PrebuiltBuildToolInfo{})
-
 func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
 	sourcePath := t.prebuilt.SingleSourcePath(ctx)
 	installedPath := PathForModuleOut(ctx, t.BaseModuleName())
@@ -93,11 +82,6 @@
 	}
 
 	t.toolPath = OptionalPathForPath(installedPath)
-
-	ctx.SetProvider(PrebuiltBuildToolInfoProvider, PrebuiltBuildToolInfo{
-		Src:  sourcePath,
-		Deps: deps,
-	})
 }
 
 func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
@@ -117,6 +101,10 @@
 
 // prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
 // in genrules with the "tools" property.
+func prebuiltBuildToolFactory() Module {
+	return NewPrebuiltBuildTool()
+}
+
 func NewPrebuiltBuildTool() Module {
 	module := &prebuiltBuildTool{}
 	module.AddProperties(&module.properties)
diff --git a/android/proto.go b/android/proto.go
index fc21d01..c449a87 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -289,7 +289,7 @@
 				attrs.Strip_import_prefix = proptools.StringPtr("")
 			}
 
-			tags := ApexAvailableTagsWithoutTestApexes(ctx.(TopDownMutatorContext), ctx.Module())
+			tags := ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 			moduleDir := ctx.ModuleDir()
 			if !canonicalPathFromRoot {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index 245b759..777c1cf 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -474,23 +474,13 @@
 		Inputs(depFiles.Paths())
 }
 
-// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
-// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables.
-func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) {
-	r.build(name, desc, false)
-}
-
 // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
 // Outputs.
 func (r *RuleBuilder) Build(name string, desc string) {
-	r.build(name, desc, true)
-}
-
-func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
 	name = ninjaNameEscape(name)
 
 	if len(r.missingDeps) > 0 {
-		r.ctx.Build(r.pctx, BuildParams{
+		r.ctx.Build(pctx, BuildParams{
 			Rule:        ErrorRule,
 			Outputs:     r.Outputs(),
 			Description: desc,
@@ -629,35 +619,12 @@
 				name, r.sboxManifestPath.String(), r.outDir.String())
 		}
 
-		// Create a rule to write the manifest as textproto.
+		// Create a rule to write the manifest as a the textproto.
 		pbText, err := prototext.Marshal(&manifest)
 		if err != nil {
 			ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
 		}
-		if ninjaEscapeCommandString {
-			WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
-		} else {
-			// We need  to have a rule to write files that is
-			// defined on the RuleBuilder's pctx in order to
-			// write Ninja variables in the string.
-			// The WriteFileRule function above rule can only write
-			// raw strings because it is defined on the android
-			// package's pctx, and it can't access variables defined
-			// in another context.
-			r.ctx.Build(r.pctx, BuildParams{
-				Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{
-					Command:        `rm -rf ${out} && cat ${out}.rsp > ${out}`,
-					Rspfile:        "${out}.rsp",
-					RspfileContent: "${content}",
-					Description:    "write file",
-				}, "content"),
-				Output:      r.sboxManifestPath,
-				Description: "write sbox manifest " + r.sboxManifestPath.Base(),
-				Args: map[string]string{
-					"content": string(pbText),
-				},
-			})
-		}
+		WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
 
 		// Generate a new string to use as the command line of the sbox rule.  This uses
 		// a RuleBuilderCommand as a convenience method of building the command line, then
@@ -756,13 +723,9 @@
 		pool = localPool
 	}
 
-	if ninjaEscapeCommandString {
-		commandString = proptools.NinjaEscape(commandString)
-	}
-
 	r.ctx.Build(r.pctx, BuildParams{
-		Rule: r.ctx.Rule(r.pctx, name, blueprint.RuleParams{
-			Command:        commandString,
+		Rule: r.ctx.Rule(pctx, name, blueprint.RuleParams{
+			Command:        proptools.NinjaEscape(commandString),
 			CommandDeps:    proptools.NinjaEscapeList(tools.Strings()),
 			Restat:         r.restat,
 			Rspfile:        proptools.NinjaEscape(rspFile),
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index a6b3a27..86647eb 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -28,17 +28,6 @@
 	"android/soong/shared"
 )
 
-var (
-	pctx_ruleBuilderTest           = NewPackageContext("android/soong/rule_builder")
-	pctx_ruleBuilderTestSubContext = NewPackageContext("android/soong/rule_builder/config")
-)
-
-func init() {
-	pctx_ruleBuilderTest.Import("android/soong/rule_builder/config")
-	pctx_ruleBuilderTest.StaticVariable("cmdFlags", "${config.ConfigFlags}")
-	pctx_ruleBuilderTestSubContext.StaticVariable("ConfigFlags", "--some-clang-flag")
-}
-
 func builderContext() BuilderContext {
 	return BuilderContextForTesting(TestConfig("out", nil, "", map[string][]byte{
 		"ld":      nil,
@@ -507,13 +496,11 @@
 type testRuleBuilderModule struct {
 	ModuleBase
 	properties struct {
-		Srcs  []string
-		Flags []string
+		Srcs []string
 
-		Restat              bool
-		Sbox                bool
-		Sbox_inputs         bool
-		Unescape_ninja_vars bool
+		Restat      bool
+		Sbox        bool
+		Sbox_inputs bool
 	}
 }
 
@@ -531,9 +518,8 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForModuleOut(ctx, "sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
-		out, outDep, outDir,
-		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
+		manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
@@ -557,18 +543,17 @@
 	rspFileContents2 := PathsForSource(ctx, []string{"rsp_in2"})
 	manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
 
-	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
-		manifestPath, true, false, false, false,
+	testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, out, outDep, outDir,
+		manifestPath, true, false, false,
 		rspFile, rspFileContents, rspFile2, rspFileContents2)
 }
 
 func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
-	flags []string,
 	out, outDep, outDir, manifestPath WritablePath,
-	restat, sbox, sboxInputs, unescapeNinjaVars bool,
+	restat, sbox, sboxInputs bool,
 	rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
 
-	rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
+	rule := NewRuleBuilder(pctx, ctx)
 
 	if sbox {
 		rule.Sbox(outDir, manifestPath)
@@ -579,7 +564,6 @@
 
 	rule.Command().
 		Tool(PathForSource(ctx, "cp")).
-		Flags(flags).
 		Inputs(in).
 		Implicit(implicit).
 		OrderOnly(orderOnly).
@@ -593,11 +577,7 @@
 		rule.Restat()
 	}
 
-	if unescapeNinjaVars {
-		rule.BuildWithUnescapedNinjaVars("rule", "desc")
-	} else {
-		rule.Build("rule", "desc")
-	}
+	rule.Build("rule", "desc")
 }
 
 var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -812,47 +792,3 @@
 		})
 	}
 }
-
-func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
-	bp := `
-		rule_builder_test {
-			name: "foo_sbox_escaped_ninja",
-			flags: ["${cmdFlags}"],
-			sbox: true,
-			sbox_inputs: true,
-		}
-		rule_builder_test {
-			name: "foo_sbox",
-			flags: ["${cmdFlags}"],
-			sbox: true,
-			sbox_inputs: true,
-			unescape_ninja_vars: true,
-		}
-	`
-	result := GroupFixturePreparers(
-		prepareForRuleBuilderTest,
-		FixtureWithRootAndroidBp(bp),
-	).RunTest(t)
-
-	escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped_ninja", "").Rule("writeFile")
-	AssertStringDoesContain(
-		t,
-		"",
-		escapedNinjaMod.BuildParams.Args["content"],
-		"$${cmdFlags}",
-	)
-
-	unescapedNinjaMod := result.ModuleForTests("foo_sbox", "").Rule("unescapedWriteFile")
-	AssertStringDoesContain(
-		t,
-		"",
-		unescapedNinjaMod.BuildParams.Args["content"],
-		"${cmdFlags}",
-	)
-	AssertStringDoesNotContain(
-		t,
-		"",
-		unescapedNinjaMod.BuildParams.Args["content"],
-		"$${cmdFlags}",
-	)
-}
diff --git a/android/util.go b/android/util.go
index 7f6af2d..5375373 100644
--- a/android/util.go
+++ b/android/util.go
@@ -33,17 +33,12 @@
 	return append([]T{}, s...)
 }
 
-// Concat returns a new slice concatenated from the input slices. It does not change the input
+// Concat returns a new slice concatenated from the two input slices. It does not change the input
 // slices.
-func Concat[T any](slices ...[]T) []T {
-	newLength := 0
-	for _, s := range slices {
-		newLength += len(s)
-	}
-	res := make([]T, 0, newLength)
-	for _, s := range slices {
-		res = append(res, s...)
-	}
+func Concat[T any](s1, s2 []T) []T {
+	res := make([]T, 0, len(s1)+len(s2))
+	res = append(res, s1...)
+	res = append(res, s2...)
 	return res
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 3a6af1e..9475f5d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -948,7 +948,7 @@
 	// Ensure that stub dependency from a rust module is not included
 	ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so")
 	// The rust module is linked to the stub cc library
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").Args["linkFlags"]
 	ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so")
 	ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so")
 
@@ -1024,7 +1024,7 @@
 	mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
 	ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so")
 	ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
-	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").RuleParams.Command
+	rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustLink").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")
 }
diff --git a/bazel/aquery.go b/bazel/aquery.go
index c355712..7195a97 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -18,14 +18,16 @@
 	"crypto/sha256"
 	"encoding/base64"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"path/filepath"
-	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
 	"reflect"
 	"sort"
 	"strings"
 	"sync"
 
+	analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
+
 	"github.com/google/blueprint/metrics"
 	"github.com/google/blueprint/proptools"
 	"google.golang.org/protobuf/proto"
@@ -374,9 +376,14 @@
 		for i, actionEntry := range aqueryProto.Actions {
 			wg.Add(1)
 			go func(i int, actionEntry *analysis_v2_proto.Action) {
-				buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry)
-				if aErr != nil {
+				if buildStatement, aErr := aqueryHandler.actionToBuildStatement(actionEntry); aErr != nil {
 					errOnce.Do(func() {
+						for _, t := range aqueryProto.Targets {
+							if t.GetId() == actionEntry.GetTargetId() {
+								aErr = fmt.Errorf("%s: [%s] [%s]", aErr.Error(), actionEntry.GetMnemonic(), t.GetLabel())
+								break
+							}
+						}
 						err = aErr
 					})
 				} else {
@@ -782,7 +789,7 @@
 	}
 
 	if len(actionEntry.Arguments) < 1 {
-		return nil, fmt.Errorf("received action with no command: [%s]", actionEntry.Mnemonic)
+		return nil, errors.New("received action with no command")
 	}
 	return a.normalActionBuildStatement(actionEntry)
 
diff --git a/bp2build/aar_conversion_test.go b/bp2build/aar_conversion_test.go
index 59aacbb..40356a1 100644
--- a/bp2build/aar_conversion_test.go
+++ b/bp2build/aar_conversion_test.go
@@ -110,7 +110,7 @@
 				"import.aar": "",
 				"dep.aar":    "",
 			},
-			StubbedBuildDefinitions: []string{"static_lib_dep", "prebuilt_static_import_dep"},
+			StubbedBuildDefinitions: []string{"static_lib_dep", "static_import_dep", "static_import_dep-neverlink"},
 			// Bazel's aar_import can only export *_import targets, so we expect
 			// only "static_import_dep" in exports, but both "static_lib_dep" and
 			// "static_import_dep" in deps
@@ -125,6 +125,7 @@
 // TODO: b/301007952 - This dep is needed because android_library_import must have aars set.
 android_library_import {
         name: "static_import_dep",
+        aars: ["import.aar"],
 }
 `,
 			ExpectedBazelTargets: []string{
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 60de28c..5871d59 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -112,7 +112,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -609,7 +609,7 @@
 }
 
 cc_binary { name: "cc_binary_1" }
-sh_binary { name: "sh_binary_2" }
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex {
 	name: "com.android.apogee",
@@ -736,7 +736,7 @@
 }
 
 cc_binary { name: "cc_binary_1"}
-sh_binary { name: "sh_binary_2"}
+sh_binary { name: "sh_binary_2", src: "foo.sh"}
 
 apex_test {
 	name: "com.android.apogee",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 15b7766..e6941df 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -713,27 +713,32 @@
 
 		switch ctx.Mode() {
 		case Bp2Build:
-			// There are two main ways of converting a Soong module to Bazel:
-			// 1) Manually handcrafting a Bazel target and associating the module with its label
-			// 2) Automatically generating with bp2build converters
-			//
-			// bp2build converters are used for the majority of modules.
-			if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
-				if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
-					panic(fmt.Errorf("module %q [%s] [%s] was both converted with bp2build and has a handcrafted label", bpCtx.ModuleName(m), moduleType, dir))
-				}
-				// Handle modules converted to handcrafted targets.
-				//
-				// Since these modules are associated with some handcrafted
-				// target in a BUILD file, we don't autoconvert them.
+			if aModule, ok := m.(android.Module); ok {
+				reason := aModule.GetUnconvertedReason()
+				if reason != nil {
+					// If this module was force-enabled, cause an error.
+					if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
+						err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
+						errs = append(errs, err)
+					}
 
-				// Log the module.
-				metrics.AddUnconvertedModule(m, moduleType, dir,
-					android.UnconvertedReason{
-						ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE),
-					})
-			} else if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
+					// Log the module isn't to be converted by bp2build.
+					// TODO: b/291598248 - Log handcrafted modules differently than other unconverted modules.
+					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
+					return
+				}
+				if len(aModule.Bp2buildTargets()) == 0 {
+					panic(fmt.Errorf("illegal bp2build invariant: module '%s' was neither converted nor marked unconvertible", aModule.Name()))
+				}
+
 				// Handle modules converted to generated targets.
+				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
+				errs = append(errs, targetErrs...)
+				for _, t := range targets {
+					// A module can potentially generate more than 1 Bazel
+					// target, each of a different rule class.
+					metrics.IncrementRuleClassCount(t.ruleClass)
+				}
 
 				// Log the module.
 				metrics.AddConvertedModule(aModule, moduleType, dir)
@@ -761,24 +766,6 @@
 						return
 					}
 				}
-				targets, targetErrs = generateBazelTargets(bpCtx, aModule)
-				errs = append(errs, targetErrs...)
-				for _, t := range targets {
-					// A module can potentially generate more than 1 Bazel
-					// target, each of a different rule class.
-					metrics.IncrementRuleClassCount(t.ruleClass)
-				}
-			} else if _, ok := ctx.Config().BazelModulesForceEnabledByFlag()[m.Name()]; ok && m.Name() != "" {
-				err := fmt.Errorf("Force Enabled Module %s not converted", m.Name())
-				errs = append(errs, err)
-			} else if aModule, ok := m.(android.Module); ok {
-				reason := aModule.GetUnconvertedReason()
-				if reason == nil {
-					panic(fmt.Errorf("module '%s' was neither converted nor marked unconvertible with bp2build", aModule.Name()))
-				} else {
-					metrics.AddUnconvertedModule(m, moduleType, dir, *reason)
-				}
-				return
 			} else if glib, ok := m.(*bootstrap.GoPackage); ok {
 				targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
 				errs = append(errs, targetErrs...)
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 329c907..afbfffa 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1994,6 +1994,41 @@
 	})
 }
 
+func TestAlreadyPresentOneToManyBuildTarget(t *testing.T) {
+	bp := `
+	custom {
+		name: "foo",
+    one_to_many_prop: true,
+	}
+	custom {
+		name: "bar",
+	}
+	`
+	alreadyPresentBuildFile :=
+		MakeBazelTarget(
+			"custom",
+			// one_to_many_prop ensures that foo generates "foo_proto_library_deps".
+			"foo_proto_library_deps",
+			AttrNameToString{},
+		)
+	expectedBazelTargets := []string{
+		MakeBazelTarget(
+			"custom",
+			"bar",
+			AttrNameToString{},
+		),
+	}
+	registerCustomModule := func(ctx android.RegistrationContext) {
+		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
+	}
+	RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
+		AlreadyExistingBuildContents: alreadyPresentBuildFile,
+		Blueprint:                    bp,
+		ExpectedBazelTargets:         expectedBazelTargets,
+		Description:                  "Not duplicating work for an already-present BUILD target (different generated name)",
+	})
+}
+
 // Verifies that if a module is defined in pkg1/Android.bp, that a target present
 // in pkg2/BUILD.bazel does not result in the module being labeled "already defined
 // in a BUILD file".
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index bdde996..6fa14e3 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -1595,7 +1595,7 @@
 		Description:                "cc_library_shared stubs",
 		ModuleTypeUnderTest:        "cc_library_shared",
 		ModuleTypeUnderTestFactory: cc.LibrarySharedFactory,
-		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs"},
+		StubbedBuildDefinitions:    []string{"libNoStubs", "libHasApexStubs", "libHasApexAndNdkStubs", "libHasApexAndNdkStubs.ndk_stub_libs"},
 		Blueprint: soongCcLibrarySharedPreamble + `
 cc_library_shared {
 	name: "libUsesSdk",
@@ -1621,9 +1621,7 @@
 }
 ndk_library {
 	name: "libHasApexAndNdkStubs",
-	// TODO: b/301321658 - Stub this once existing-build-file handling can deal with
-	// modules that generate targets of a different name.
-	bazel_module: { bp2build_available: false },
+	first_version: "28",
 }
 `,
 		ExpectedBazelTargets: []string{
diff --git a/bp2build/java_binary_host_conversion_test.go b/bp2build/java_binary_host_conversion_test.go
index 7d8ab63..4271f76 100644
--- a/bp2build/java_binary_host_conversion_test.go
+++ b/bp2build/java_binary_host_conversion_test.go
@@ -114,7 +114,7 @@
 	runJavaBinaryHostTestCase(t, Bp2buildTestCase{
 		Description:             "java_binary_host with srcs, libs.",
 		Filesystem:              testFs,
-		StubbedBuildDefinitions: []string{"prebuilt_java-lib-dep-1"},
+		StubbedBuildDefinitions: []string{"java-lib-dep-1", "java-lib-dep-1-neverlink"},
 		Blueprint: `java_binary_host {
     name: "java-binary-host-libs",
     libs: ["java-lib-dep-1"],
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index 3d55eb2..4e96efe 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -141,17 +141,22 @@
 func TestJavaLibsAndOnlyProtoSrcs(t *testing.T) {
 	runJavaProtoTestCase(t, Bp2buildTestCase{
 		Description:             "java_library that has only proto srcs",
-		StubbedBuildDefinitions: []string{"java-lib"},
+		StubbedBuildDefinitions: []string{"java-lib-1", "java-lib-2"},
 		Blueprint: `java_library_static {
     name: "java-protos",
     srcs: ["a.proto"],
-    libs: ["java-lib"],
+    libs: ["java-lib-1"],
+    static_libs: ["java-lib-2"],
     java_version: "7",
     sdk_version: "current",
 }
 
 java_library_static {
-    name: "java-lib",
+    name: "java-lib-1",
+}
+
+java_library_static {
+    name: "java-lib-2",
 }
 `,
 		ExpectedBazelTargets: []string{
@@ -162,12 +167,19 @@
 				"java_lite_proto_library",
 				"java-protos_java_proto_lite",
 				AttrNameToString{
-					"deps":         `[":java-protos_proto"]`,
+					"deps": `[":java-protos_proto"]`,
+					"additional_proto_deps": `[
+        ":java-lib-1-neverlink",
+        ":java-lib-2",
+    ]`,
 					"java_version": `"7"`,
 					"sdk_version":  `"current"`,
 				}),
 			MakeBazelTarget("java_library", "java-protos", AttrNameToString{
-				"exports":      `[":java-protos_java_proto_lite"]`,
+				"exports": `[
+        ":java-lib-2",
+        ":java-protos_java_proto_lite",
+    ]`,
 				"java_version": `"7"`,
 				"sdk_version":  `"current"`,
 			}),
diff --git a/bp2build/testing.go b/bp2build/testing.go
index a810709..dfd4d57 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -571,23 +571,6 @@
 	)
 }
 
-var _ android.ApiProvider = (*customModule)(nil)
-
-func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class: "custom_api_contribution",
-	}
-	apiAttribute := bazel.MakeLabelAttribute(
-		android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
-	)
-	attrs := &customBazelModuleAttributes{
-		Api: *apiAttribute,
-	}
-	ctx.CreateBazelTargetModule(props,
-		android.CommonAttributes{Name: c.Name()},
-		attrs)
-}
-
 // A bp2build mutator that uses load statements and creates a 1:M mapping from
 // module to target.
 func customBp2buildOneToMany(ctx android.Bp2buildMutatorContext, m *customModule) {
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 569f721..5dc119e 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -223,7 +223,7 @@
 }
 
 // bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
-func bp2BuildParseLibProps(ctx android.BazelConversionPathContext, module *Module, isStatic bool) staticOrSharedAttributes {
+func bp2BuildParseLibProps(ctx android.Bp2buildMutatorContext, module *Module, isStatic bool) staticOrSharedAttributes {
 	lib, ok := module.compiler.(*libraryDecorator)
 	if !ok {
 		return staticOrSharedAttributes{}
@@ -232,12 +232,12 @@
 }
 
 // bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
+func bp2BuildParseSharedProps(ctx android.Bp2buildMutatorContext, module *Module) staticOrSharedAttributes {
 	return bp2BuildParseLibProps(ctx, module, false)
 }
 
 // bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
-func bp2BuildParseStaticProps(ctx android.BazelConversionPathContext, module *Module) staticOrSharedAttributes {
+func bp2BuildParseStaticProps(ctx android.Bp2buildMutatorContext, module *Module) staticOrSharedAttributes {
 	return bp2BuildParseLibProps(ctx, module, true)
 }
 
@@ -288,7 +288,7 @@
 }
 
 // Parses properties common to static and shared libraries. Also used for prebuilt libraries.
-func bp2buildParseStaticOrSharedProps(ctx android.BazelConversionPathContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
+func bp2buildParseStaticOrSharedProps(ctx android.Bp2buildMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
 	attrs := staticOrSharedAttributes{}
 
 	setAttrs := func(axis bazel.ConfigurationAxis, config string, props StaticOrSharedProperties) {
@@ -334,7 +334,7 @@
 	attrs.Srcs_c = partitionedSrcs[cSrcPartition]
 	attrs.Srcs_as = partitionedSrcs[asSrcPartition]
 
-	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), apexAvailable)
+	attrs.Apex_available = android.ConvertApexAvailableToTagsWithoutTestApexes(ctx, apexAvailable)
 
 	attrs.Features.Append(convertHiddenVisibilityToFeatureStaticOrShared(ctx, module, isStatic))
 
@@ -1143,7 +1143,7 @@
 	compilerAttrs compilerAttributes,
 ) *bazel.LabelAttribute {
 	var aidlLibsFromSrcs, aidlFiles bazel.LabelListAttribute
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 
 	if !aidlSrcs.IsEmpty() {
 		aidlLibsFromSrcs, aidlFiles = aidlSrcs.Partition(func(src bazel.Label) bool {
@@ -1283,7 +1283,7 @@
 	la.implementationDeps.Append(staticExcludesLabelList)
 }
 
-func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.BazelConversionPathContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
+func (la *linkerAttributes) bp2buildForAxisAndConfig(ctx android.Bp2buildMutatorContext, module *Module, axis bazel.ConfigurationAxis, config string, props *BaseLinkerProperties) {
 	isBinary := module.Binary()
 	// Use a single variable to capture usage of nocrt in arch variants, so there's only 1 error message for this module
 	var axisFeatures []string
@@ -1490,7 +1490,7 @@
 // Note that this is an anti-pattern: The config_setting should be created from the apex definition
 // and not from a cc_library.
 // This anti-pattern is needed today since not all apexes have been allowlisted.
-func createInApexConfigSetting(ctx android.TopDownMutatorContext, apexName string) {
+func createInApexConfigSetting(ctx android.Bp2buildMutatorContext, apexName string) {
 	if apexName == android.AvailableToPlatform || apexName == android.AvailableToAnyApex {
 		// These correspond to android-non_apex and android-in_apex
 		return
@@ -1587,13 +1587,13 @@
 	return exists && ctx.OtherModuleType(mod) == "ndk_library"
 }
 
-func SetStubsForDynamicDeps(ctx android.BazelConversionPathContext, axis bazel.ConfigurationAxis,
+func SetStubsForDynamicDeps(ctx android.Bp2buildMutatorContext, axis bazel.ConfigurationAxis,
 	config string, apexAvailable []string, dynamicLibs bazel.LabelList, dynamicDeps *bazel.LabelListAttribute, ind int, buildNonApexWithStubs bool) {
 
 	// Create a config_setting for each apex_available.
 	// This will be used to select impl of a dep if dep is available to the same apex.
 	for _, aa := range apexAvailable {
-		createInApexConfigSetting(ctx.(android.TopDownMutatorContext), aa)
+		createInApexConfigSetting(ctx, aa)
 	}
 
 	apiDomainForSelects := []string{}
diff --git a/cc/cc.go b/cc/cc.go
index 81a6cd6..1896766 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -4273,24 +4273,6 @@
 	}
 }
 
-var _ android.ApiProvider = (*Module)(nil)
-
-func (c *Module) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	if c.IsPrebuilt() {
-		return
-	}
-	switch c.typ() {
-	case fullLibrary:
-		apiContributionBp2Build(ctx, c)
-	case sharedLibrary:
-		apiContributionBp2Build(ctx, c)
-	case headerLibrary:
-		// Aggressively generate api targets for all header modules
-		// This is necessary since the header module does not know if it is a dep of API surface stub library
-		apiLibraryHeadersBp2Build(ctx, c)
-	}
-}
-
 // Defaults
 type Defaults struct {
 	android.ModuleBase
diff --git a/cc/library.go b/cc/library.go
index b9dc71b..e66ce08 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -517,70 +517,6 @@
 	}
 }
 
-func apiContributionBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	apiSurfaces := make([]string, 0)
-	apiHeaders := make([]string, 0)
-	// module-libapi for apexes (non-null `stubs` property)
-	if module.HasStubsVariants() {
-		apiSurfaces = append(apiSurfaces, android.ModuleLibApi.String())
-		apiIncludes := getModuleLibApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// vendorapi (non-null `llndk` property)
-	if module.HasLlndkStubs() {
-		apiSurfaces = append(apiSurfaces, android.VendorApi.String())
-		apiIncludes := getVendorApiIncludes(ctx, module)
-		if !apiIncludes.isEmpty() {
-			createApiHeaderTarget(ctx, apiIncludes)
-			apiHeaders = append(apiHeaders, apiIncludes.name)
-		}
-	}
-	// create a target only if this module contributes to an api surface
-	// TODO: Currently this does not distinguish modulelibapi-only headers and vendrorapi-only headers
-	// TODO: Update so that modulelibapi-only headers do not get exported to vendorapi (and vice-versa)
-	if len(apiSurfaces) > 0 {
-		props := bazel.BazelTargetModuleProperties{
-			Rule_class:        "cc_api_contribution",
-			Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-		}
-		attrs := &bazelCcApiContributionAttributes{
-			Library_name: module.Name(),
-			Api_surfaces: bazel.MakeStringListAttribute(apiSurfaces),
-			Api:          apiLabelAttribute(ctx, module),
-			Hdrs: bazel.MakeLabelListAttribute(
-				bazel.MakeLabelListFromTargetNames(apiHeaders),
-			),
-		}
-		ctx.CreateBazelTargetModule(
-			props,
-			android.CommonAttributes{
-				Name:     android.ApiContributionTargetName(module.Name()),
-				SkipData: proptools.BoolPtr(true),
-			},
-			attrs,
-		)
-	}
-}
-
-// Native apis are versioned in a single .map.txt for all api surfaces
-// Pick any one of the .map.txt files
-func apiLabelAttribute(ctx android.TopDownMutatorContext, module *Module) bazel.LabelAttribute {
-	var apiFile *string
-	linker := module.linker.(*libraryDecorator)
-	if llndkApi := linker.Properties.Llndk.Symbol_file; llndkApi != nil {
-		apiFile = llndkApi
-	} else if moduleLibApi := linker.Properties.Stubs.Symbol_file; moduleLibApi != nil {
-		apiFile = moduleLibApi
-	} else {
-		ctx.ModuleErrorf("API surface library does not have any API file")
-	}
-	apiLabel := android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label
-	return *bazel.MakeLabelAttribute(apiLabel)
-}
-
 // wrapper struct to flatten the arch and os specific export_include_dirs
 // flattening is necessary since we want to export apis of all arches even when we build for x86 (e.g.)
 type bazelCcApiLibraryHeadersAttributes struct {
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 5eba6ab..fccdf99 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -15,8 +15,6 @@
 package cc
 
 import (
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
 	"android/soong/bazel"
 	"android/soong/bazel/cquery"
@@ -175,106 +173,6 @@
 	return bazel.MakeLabelList(labels)
 }
 
-func apiLibraryHeadersBp2Build(ctx android.TopDownMutatorContext, module *Module) {
-	// cc_api_library_headers have a 1:1 mapping to arch/no-arch
-	// For API export, create a top-level arch-agnostic target and list the arch-specific targets as its deps
-
-	// arch-agnostic includes
-	apiIncludes := getModuleLibApiIncludes(ctx, module)
-	// arch and os specific includes
-	archApiIncludes, androidOsIncludes := archOsSpecificApiIncludes(ctx, module)
-	for _, arch := range allArches { // sorted iteration
-		archApiInclude := archApiIncludes[arch]
-		if !archApiInclude.isEmpty() {
-			createApiHeaderTarget(ctx, archApiInclude)
-			apiIncludes.addDep(archApiInclude.name)
-		}
-	}
-	// os==android includes
-	if !androidOsIncludes.isEmpty() {
-		createApiHeaderTarget(ctx, androidOsIncludes)
-		apiIncludes.addDep(androidOsIncludes.name)
-	}
-
-	if !apiIncludes.isEmpty() {
-		// override the name from <mod>.module-libapi.headers --> <mod>.contribution
-		apiIncludes.name = android.ApiContributionTargetName(module.Name())
-		createApiHeaderTarget(ctx, apiIncludes)
-	}
-}
-
-func createApiHeaderTarget(ctx android.TopDownMutatorContext, includes apiIncludes) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "cc_api_library_headers",
-		Bzl_load_location: "//build/bazel/rules/apis:cc_api_contribution.bzl",
-	}
-	ctx.CreateBazelTargetModule(
-		props,
-		android.CommonAttributes{
-			Name:     includes.name,
-			SkipData: proptools.BoolPtr(true),
-		},
-		&includes.attrs,
-	)
-}
-
 var (
 	allArches = []string{"arm", "arm64", "x86", "x86_64"}
 )
-
-type archApiIncludes map[string]apiIncludes
-
-func archOsSpecificApiIncludes(ctx android.TopDownMutatorContext, module *Module) (archApiIncludes, apiIncludes) {
-	baseProps := bp2BuildParseBaseProps(ctx, module)
-	i := bp2BuildParseExportedIncludes(ctx, module, &baseProps.includes)
-	archRet := archApiIncludes{}
-	for _, arch := range allArches {
-		includes := i.Includes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		systemIncludes := i.SystemIncludes.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		deps := baseProps.deps.SelectValue(
-			bazel.ArchConfigurationAxis,
-			arch)
-		attrs := bazelCcLibraryHeadersAttributes{
-			Export_includes:        bazel.MakeStringListAttribute(includes),
-			Export_system_includes: bazel.MakeStringListAttribute(systemIncludes),
-		}
-		apiDeps := apiBazelTargets(deps)
-		if !apiDeps.IsEmpty() {
-			attrs.Deps = bazel.MakeLabelListAttribute(apiDeps)
-		}
-		apiIncludes := apiIncludes{
-			name: android.ApiContributionTargetName(module.Name()) + "." + arch,
-			attrs: bazelCcApiLibraryHeadersAttributes{
-				bazelCcLibraryHeadersAttributes: attrs,
-				Arch:                            proptools.StringPtr(arch),
-			},
-		}
-		archRet[arch] = apiIncludes
-	}
-
-	// apiIncludes for os == Android
-	androidOsDeps := baseProps.deps.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid)
-	androidOsAttrs := bazelCcLibraryHeadersAttributes{
-		Export_includes: bazel.MakeStringListAttribute(
-			i.Includes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-		Export_system_includes: bazel.MakeStringListAttribute(
-			i.SystemIncludes.SelectValue(bazel.OsConfigurationAxis, bazel.OsAndroid),
-		),
-	}
-	androidOsApiDeps := apiBazelTargets(androidOsDeps)
-	if !androidOsApiDeps.IsEmpty() {
-		androidOsAttrs.Deps = bazel.MakeLabelListAttribute(androidOsApiDeps)
-	}
-	osRet := apiIncludes{
-		name: android.ApiContributionTargetName(module.Name()) + ".androidos",
-		attrs: bazelCcApiLibraryHeadersAttributes{
-			bazelCcLibraryHeadersAttributes: androidOsAttrs,
-		},
-	}
-	return archRet, osRet
-}
diff --git a/cc/proto.go b/cc/proto.go
index 0ed4381..4e08a4c 100644
--- a/cc/proto.go
+++ b/cc/proto.go
@@ -246,7 +246,7 @@
 	protoAttrs.Min_sdk_version = m.Properties.Min_sdk_version
 
 	name := m.Name() + suffix
-	tags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), m)
+	tags := android.ApexAvailableTagsWithoutTestApexes(ctx, m)
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        rule_class,
diff --git a/cc/sysprop.go b/cc/sysprop.go
index 7ddd476..be03004 100644
--- a/cc/sysprop.go
+++ b/cc/sysprop.go
@@ -38,7 +38,7 @@
 }
 
 func Bp2buildSysprop(ctx android.Bp2buildMutatorContext, labels SyspropLibraryLabels, srcs bazel.LabelListAttribute, minSdkVersion *string) {
-	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx.(android.TopDownMutatorContext), ctx.Module())
+	apexAvailableTags := android.ApexAvailableTagsWithoutTestApexes(ctx, ctx.Module())
 	ctx.CreateBazelTargetModule(
 		bazel.BazelTargetModuleProperties{
 			Rule_class:        "sysprop_library",
diff --git a/cc/testing.go b/cc/testing.go
index 36bc261..7531f6d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -35,7 +35,6 @@
 
 	multitree.RegisterApiImportsModule(ctx)
 
-	ctx.RegisterModuleType("prebuilt_build_tool", android.NewPrebuiltBuildTool)
 	ctx.RegisterModuleType("cc_benchmark", BenchmarkFactory)
 	ctx.RegisterModuleType("cc_object", ObjectFactory)
 	ctx.RegisterModuleType("cc_genrule", GenRuleFactory)
@@ -68,26 +67,6 @@
 
 func commonDefaultModules() string {
 	return `
-		prebuilt_build_tool {
-			name: "clang++",
-			src: "bin/clang++",
-		}
-		prebuilt_build_tool {
-			name: "clang++.real",
-			src: "bin/clang++.real",
-		}
-		prebuilt_build_tool {
-			name: "lld",
-			src: "bin/lld",
-		}
-		prebuilt_build_tool {
-			name: "ld.lld",
-			src: "bin/ld.lld",
-		}
-		prebuilt_build_tool {
-			name: "llvm-ar",
-			src: "bin/llvm-ar",
-		}
 		cc_defaults {
 			name: "toolchain_libs_defaults",
 			host_supported: true,
@@ -589,12 +568,6 @@
 
 	// Additional files needed in tests that disallow non-existent source.
 	android.MockFS{
-		"defaults/cc/common/bin/clang++":      nil,
-		"defaults/cc/common/bin/clang++.real": nil,
-		"defaults/cc/common/bin/lld":          nil,
-		"defaults/cc/common/bin/ld.lld":       nil,
-		"defaults/cc/common/bin/llvm-ar":      nil,
-
 		"defaults/cc/common/libc.map.txt":      nil,
 		"defaults/cc/common/libdl.map.txt":     nil,
 		"defaults/cc/common/libm.map.txt":      nil,
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 2e71fe1..a7308b4 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -76,8 +76,8 @@
 	if err != nil {
 		return nil, err
 	}
-	bytes := make([]byte, tocFile.FileHeader.UncompressedSize64)
-	if _, err := rc.Read(bytes); err != nil && err != io.EOF {
+	bytes, err := io.ReadAll(rc)
+	if err != nil {
 		return nil, err
 	}
 	rc.Close()
diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go
index 3364f50..fc56dd5 100644
--- a/cmd/sbox/sbox.go
+++ b/cmd/sbox/sbox.go
@@ -119,9 +119,6 @@
 	}
 
 	manifest, err := readManifest(manifestFile)
-	if err != nil {
-		return err
-	}
 
 	if len(manifest.Commands) == 0 {
 		return fmt.Errorf("at least one commands entry is required in %q", manifestFile)
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 1d5dd76..67a55bd 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -24,7 +24,6 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
-	"android/soong/bazel"
 	"android/soong/java/config"
 	"android/soong/remoteexec"
 )
@@ -855,34 +854,6 @@
 	}
 }
 
-var _ android.ApiProvider = (*Droidstubs)(nil)
-
-type bazelJavaApiContributionAttributes struct {
-	Api         bazel.LabelAttribute
-	Api_surface *string
-}
-
-func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
-	props := bazel.BazelTargetModuleProperties{
-		Rule_class:        "java_api_contribution",
-		Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
-	}
-	apiFile := d.properties.Check_api.Current.Api_file
-	// Do not generate a target if check_api is not set
-	if apiFile == nil {
-		return
-	}
-	attrs := &bazelJavaApiContributionAttributes{
-		Api: *bazel.MakeLabelAttribute(
-			android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
-		),
-		Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
-	}
-	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: android.ApiContributionTargetName(ctx.ModuleName()),
-	}, attrs)
-}
-
 func (d *Droidstubs) createApiContribution(ctx android.DefaultableHookContext) {
 	api_file := d.properties.Check_api.Current.Api_file
 	api_surface := d.properties.Api_surface
diff --git a/java/java.go b/java/java.go
index d5aeb7c..fbad4f3 100644
--- a/java/java.go
+++ b/java/java.go
@@ -3067,17 +3067,6 @@
 		}
 	}
 
-	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition])
-	// Soong does not differentiate between a java_library and the Bazel equivalent of
-	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
-	// listed directly in the srcs of a java_library, and the classes produced
-	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
-	// that depend on a java_library with proto sources can link directly to the protobuf API,
-	// and so this should be a static dependency.
-	if protoDepLabel != nil {
-		staticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
-	}
-
 	depLabels := &javaDependencyLabels{}
 	depLabels.Deps = deps
 
@@ -3093,6 +3082,20 @@
 	}
 	depLabels.StaticDeps.Append(staticDeps)
 
+	var additionalProtoDeps bazel.LabelListAttribute
+	additionalProtoDeps.Append(depLabels.Deps)
+	additionalProtoDeps.Append(depLabels.StaticDeps)
+	protoDepLabel := bp2buildProto(ctx, &m.Module, srcPartitions[protoSrcPartition], additionalProtoDeps)
+	// Soong does not differentiate between a java_library and the Bazel equivalent of
+	// a java_proto_library + proto_library pair. Instead, in Soong proto sources are
+	// listed directly in the srcs of a java_library, and the classes produced
+	// by protoc are included directly in the resulting JAR. Thus upstream dependencies
+	// that depend on a java_library with proto sources can link directly to the protobuf API,
+	// and so this should be a static dependency.
+	if protoDepLabel != nil {
+		depLabels.StaticDeps.Append(bazel.MakeSingleLabelListAttribute(*protoDepLabel))
+	}
+
 	hasKotlin := !kotlinSrcs.IsEmpty()
 	commonAttrs.kotlinAttributes = &kotlinAttributes{
 		Kotlincflags: &m.properties.Kotlincflags,
diff --git a/java/proto.go b/java/proto.go
index 2ed7b27..48adadc 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -151,11 +151,17 @@
 	// a specific .proto file module explicitly.
 	Transitive_deps bazel.LabelListAttribute
 
+	// This is the libs and the static_libs of the original java_library module.
+	// On the bazel side, after proto sources are generated in java_*_proto_library, a java_library
+	// will compile them. The libs and static_libs from the original java_library module need
+	// to be linked because they are necessary in compile-time classpath.
+	Additional_proto_deps bazel.LabelListAttribute
+
 	Sdk_version  bazel.StringAttribute
 	Java_version bazel.StringAttribute
 }
 
-func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute) *bazel.Label {
+func bp2buildProto(ctx android.Bp2buildMutatorContext, m *Module, protoSrcs bazel.LabelListAttribute, AdditionalProtoDeps bazel.LabelListAttribute) *bazel.Label {
 	protoInfo, ok := android.Bp2buildProtoProperties(ctx, &m.ModuleBase, protoSrcs)
 	if !ok {
 		return nil
@@ -184,10 +190,11 @@
 	}
 
 	protoAttrs := &protoAttributes{
-		Deps:            bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
-		Transitive_deps: bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
-		Java_version:    bazel.StringAttribute{Value: m.properties.Java_version},
-		Sdk_version:     bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
+		Deps:                  bazel.MakeLabelListAttribute(protoInfo.Proto_libs),
+		Transitive_deps:       bazel.MakeLabelListAttribute(protoInfo.Transitive_proto_libs),
+		Additional_proto_deps: AdditionalProtoDeps,
+		Java_version:          bazel.StringAttribute{Value: m.properties.Java_version},
+		Sdk_version:           bazel.StringAttribute{Value: m.deviceProperties.Sdk_version},
 	}
 
 	name := m.Name() + suffix
diff --git a/rust/afdo_test.go b/rust/afdo_test.go
index 80327af..0cdf704 100644
--- a/rust/afdo_test.go
+++ b/rust/afdo_test.go
@@ -54,8 +54,8 @@
 
 	expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo")
 
-	if !strings.Contains(foo.RuleParams.Command, expectedCFlag) {
-		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in command %q", expectedCFlag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["rustcFlags"], expectedCFlag) {
+		t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", expectedCFlag, foo.Args["rustcFlags"])
 	}
 }
 
@@ -96,17 +96,17 @@
 		rustMockedFiles.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Description("rustc")
-	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Description("rustc")
+	fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc")
+	fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
 
 	expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo")
 	expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo")
 
-	if !strings.Contains(fooArm.RuleParams.Command, expectedCFlagArm) {
-		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in command %q", expectedCFlagArm, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm.Args["rustcFlags"], expectedCFlagArm) {
+		t.Errorf("Expected 'fooArm' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm, fooArm.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(fooArm64.RuleParams.Command, expectedCFlagArm64) {
-		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in command %q", expectedCFlagArm64, fooArm.RuleParams.Command)
+	if !strings.Contains(fooArm64.Args["rustcFlags"], expectedCFlagArm64) {
+		t.Errorf("Expected 'fooArm64' to enable afdo, but did not find %q in cflags %q", expectedCFlagArm64, fooArm64.Args["rustcFlags"])
 	}
 }
diff --git a/rust/binary.go b/rust/binary.go
index 353381d..1408ff1 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -138,17 +138,13 @@
 
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
+	srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	ret := buildOutput{outputFile: outputFile}
-	var crateRootPath android.Path
-	if binary.baseCompiler.Properties.Crate_root == nil {
-		crateRootPath, _ = srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
-	} else {
-		crateRootPath = android.PathForModuleSrc(ctx, *binary.baseCompiler.Properties.Crate_root)
-	}
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
 
 	if binary.stripper.NeedsStrip(ctx) {
 		strippedOutputFile := outputFile
@@ -159,7 +155,7 @@
 	}
 	binary.baseCompiler.unstrippedOutputFile = outputFile
 
-	ret.kytheFile = TransformSrcToBinary(ctx, binary, crateRootPath, deps, flags, outputFile).kytheFile
+	ret.kytheFile = TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile).kytheFile
 	return ret
 }
 
diff --git a/rust/binary_test.go b/rust/binary_test.go
index ab1d2bc..dff94ac 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -135,7 +135,7 @@
 
 	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
 
-	flags := fizzBuzz.RuleParams.Command
+	flags := fizzBuzz.Args["rustcFlags"]
 	if strings.Contains(flags, "--test") {
 		t.Errorf("extra --test flag, rustcFlags: %#v", flags)
 	}
@@ -150,11 +150,11 @@
 			bootstrap: true,
 		}`)
 
-	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc")
+	foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustLink")
 
 	flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64"
-	if !strings.Contains(foo.RuleParams.Command, flag) {
-		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, command: %#v", flag, foo.RuleParams.Command)
+	if !strings.Contains(foo.Args["linkFlags"], flag) {
+		t.Errorf("missing link flag to use bootstrap linker, expecting %#v, linkFlags: %#v", flag, foo.Args["linkFlags"])
 	}
 }
 
@@ -167,17 +167,19 @@
 		}`)
 
 	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.RuleParams.Command
+	flags := fizzOut.Args["rustcFlags"]
+	linkFlags := fizzOutLink.Args["linkFlags"]
 	if !strings.Contains(flags, "-C relocation-model=static") {
-		t.Errorf("static binary missing '-C relocation-model=static' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C relocation-model=static' in rustcFlags, found: %#v", flags)
 	}
 	if !strings.Contains(flags, "-C panic=abort") {
-		t.Errorf("static binary missing '-C panic=abort' in command, found: %#v", flags)
+		t.Errorf("static binary missing '-C panic=abort' in rustcFlags, found: %#v", flags)
 	}
-	if !strings.Contains(flags, "-static") {
-		t.Errorf("static binary missing '-static' in command, found: %#v", flags)
+	if !strings.Contains(linkFlags, "-static") {
+		t.Errorf("static binary missing '-static' in linkFlags, found: %#v", flags)
 	}
 
 	if !android.InList("libc", fizzMod.Properties.AndroidMkStaticLibs) {
@@ -199,9 +201,10 @@
 			name: "libfoo",
 		}`)
 
-	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc")
-	if !strings.Contains(fizzBuzz.RuleParams.Command, "/libfoo.so") {
-		t.Errorf("missing shared dependency 'libfoo.so' in command: %#v", fizzBuzz.RuleParams.Command)
+	fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustLink")
+	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 09933d3..b1f049d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -15,18 +15,64 @@
 package rust
 
 import (
-	"fmt"
 	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint"
 
 	"android/soong/android"
-	cc_config "android/soong/cc/config"
 	"android/soong/rust/config"
 )
 
 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 " +
+				"--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
+			CommandDeps: []string{"$rustcCmd", "$mkcraterspCmd"},
+			// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+			// Rustc emits unneeded dependency lines for the .d and input .rs files.
+			// Those extra lines cause ninja warning:
+			//     "warning: depfile has multiple output paths"
+			// For ninja, we keep/grep only the dependency rule for the rust $out file.
+			Deps:    blueprint.DepsGCC,
+			Depfile: "$out.d",
+		},
+		"rustcFlags", "libFlags", "envVars")
+	rustLink = pctx.AndroidStaticRule("rustLink",
+		blueprint.RuleParams{
+			Command: "${config.RustLinker} -o $out ${crtBegin} ${earlyLinkFlags} @$in ${linkFlags} ${crtEnd}",
+		},
+		"earlyLinkFlags", "linkFlags", "crtBegin", "crtEnd")
+
+	_       = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc")
+	rustdoc = pctx.AndroidStaticRule("rustdoc",
+		blueprint.RuleParams{
+			Command: "$envVars $rustdocCmd $rustdocFlags $in -o $outDir && " +
+				"touch $out",
+			CommandDeps: []string{"$rustdocCmd"},
+		},
+		"rustdocFlags", "outDir", "envVars")
+
+	_            = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+	clippyDriver = pctx.AndroidStaticRule("clippy",
+		blueprint.RuleParams{
+			Command: "$envVars $clippyCmd " +
+				// Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+				// Use the metadata output as it has the smallest footprint.
+				"--emit metadata -o $out --emit dep-info=$out.d.raw $in ${libFlags} " +
+				"$rustcFlags $clippyFlags" +
+				" && grep \"^$out:\" $out.d.raw > $out.d",
+			CommandDeps: []string{"$clippyCmd"},
+			Deps:        blueprint.DepsGCC,
+			Depfile:     "$out.d",
+		},
+		"rustcFlags", "libFlags", "clippyFlags", "envVars")
+
 	zip = pctx.AndroidStaticRule("zip",
 		blueprint.RuleParams{
 			Command:        "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
@@ -35,7 +81,7 @@
 			RspfileContent: "$in",
 		})
 
-	cpDir = pctx.AndroidStaticRule("cpDir",
+	cp = pctx.AndroidStaticRule("cp",
 		blueprint.RuleParams{
 			Command:        "cp `cat $outDir.rsp` $outDir",
 			Rspfile:        "${outDir}.rsp",
@@ -43,12 +89,6 @@
 		},
 		"outDir")
 
-	cp = pctx.AndroidStaticRule("cp",
-		blueprint.RuleParams{
-			Command:     "rm -f $out && cp $in $out",
-			Description: "cp $out",
-		})
-
 	// Cross-referencing:
 	_ = pctx.SourcePathVariable("rustExtractor",
 		"prebuilts/build-tools/${config.HostPrebuiltTag}/bin/rust_extractor")
@@ -56,6 +96,23 @@
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() })
 	_ = pctx.VariableFunc("kytheCuEncoding",
 		func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() })
+	_            = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json")
+	kytheExtract = pctx.AndroidStaticRule("kythe",
+		blueprint.RuleParams{
+			Command: `KYTHE_CORPUS=${kytheCorpus} ` +
+				`KYTHE_OUTPUT_FILE=$out ` +
+				`KYTHE_VNAMES=$kytheVnames ` +
+				`KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+				`KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
+				`$rustExtractor $envVars ` +
+				`$rustcCmd ` +
+				`-C linker=true ` +
+				`$in ${libFlags} $rustcFlags`,
+			CommandDeps:    []string{"$rustExtractor", "$kytheVnames"},
+			Rspfile:        "${out}.rsp",
+			RspfileContent: "$in",
+		},
+		"rustcFlags", "libFlags", "envVars")
 )
 
 type buildOutput struct {
@@ -67,40 +124,40 @@
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 }
 
-func TransformSrcToBinary(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "bin")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
 }
 
-func TransformSrctoRlib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "rlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
 }
 
-func TransformSrctoDylib(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
 
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "dylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
 }
 
-func TransformSrctoStatic(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "staticlib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
 }
 
-func TransformSrctoShared(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath) buildOutput {
 	flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "cdylib")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
 }
 
-func TransformSrctoProcMacro(ctx ModuleContext, c compiler, mainSrc android.Path, deps PathDeps,
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
 	flags Flags, outputFile android.WritablePath) buildOutput {
-	return transformSrctoCrate(ctx, c, mainSrc, deps, flags, outputFile, "proc-macro")
+	return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
 }
 
 func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -111,46 +168,28 @@
 	return paths
 }
 
-func makeLibFlags(deps PathDeps, ruleCmd *android.RuleBuilderCommand) []string {
+func makeLibFlags(deps PathDeps) []string {
 	var libFlags []string
 
 	// Collect library/crate flags
-	for _, lib := range deps.Rlibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.RLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, lib := range deps.Dylibs.ToListDirect() {
-		libPath := ruleCmd.PathForInput(lib.Path)
-		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+libPath)
+	for _, lib := range deps.DyLibs {
+		libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String())
 	}
-	for _, procMacro := range deps.ProcMacros.ToListDirect() {
-		procMacroPath := ruleCmd.PathForInput(procMacro.Path)
-		libFlags = append(libFlags, "--extern "+procMacro.CrateName+"="+procMacroPath)
+	for _, proc_macro := range deps.ProcMacros {
+		libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
 	}
 
 	for _, path := range deps.linkDirs {
-		libFlags = append(libFlags, "-L "+ruleCmd.PathForInput(path))
+		libFlags = append(libFlags, "-L "+path)
 	}
 
 	return libFlags
 }
 
-func collectImplicits(deps PathDeps) android.Paths {
-	depPaths := android.Paths{}
-	depPaths = append(depPaths, rustLibsToPaths(deps.Rlibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.Dylibs.ToList())...)
-	depPaths = append(depPaths, rustLibsToPaths(deps.ProcMacros.ToList())...)
-	depPaths = append(depPaths, deps.AfdoProfiles...)
-	depPaths = append(depPaths, deps.WholeStaticLibs...)
-	depPaths = append(depPaths, deps.SrcDeps...)
-	depPaths = append(depPaths, deps.srcProviderFiles...)
-	depPaths = append(depPaths, deps.LibDeps...)
-	depPaths = append(depPaths, deps.linkObjects...)
-	depPaths = append(depPaths, deps.BuildToolSrcDeps...)
-	return depPaths
-}
-
-func rustEnvVars(ctx ModuleContext, deps PathDeps, cmd *android.RuleBuilderCommand) []string {
+func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
 	var envVars []string
 
 	// libstd requires a specific environment variable to be set. This is
@@ -164,17 +203,15 @@
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
 		// We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
 		// assumes that paths are relative to the source file.
-		var outDir string
-		if filepath.IsAbs(moduleGenDir.String()) {
-			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
-			outDir = moduleGenDir.String()
-		} else if moduleGenDir.Valid() {
+		var outDirPrefix string
+		if !filepath.IsAbs(moduleGenDir.String()) {
 			// If OUT_DIR is not absolute, we use $$PWD to generate an absolute path (os.Getwd() returns '/')
-			outDir = filepath.Join("$$PWD/", cmd.PathForInput(moduleGenDir.Path()))
+			outDirPrefix = "$$PWD/"
 		} else {
-			outDir = "$$PWD/"
+			// If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything.
+			outDirPrefix = ""
 		}
-		envVars = append(envVars, "OUT_DIR="+outDir)
+		envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String()))
 	} else {
 		// TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value.
 		envVars = append(envVars, "OUT_DIR=out")
@@ -205,9 +242,7 @@
 		}
 	}
 
-	envVars = append(envVars, "AR="+cmd.PathForInput(
-		cc_config.ClangPath(ctx, "bin/llvm-ar")),
-	)
+	envVars = append(envVars, "AR=${cc_config.ClangBin}/llvm-ar")
 
 	if ctx.Darwin() {
 		envVars = append(envVars, "ANDROID_RUST_DARWIN=true")
@@ -216,18 +251,21 @@
 	return envVars
 }
 
-func transformSrctoCrate(ctx ModuleContext, comp compiler, main android.Path, deps PathDeps, flags Flags,
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
 	outputFile android.WritablePath, crateType string) buildOutput {
 
 	var inputs android.Paths
+	var implicits, linkImplicits, linkOrderOnly android.Paths
 	var output buildOutput
 	var rustcFlags, linkFlags []string
-	var earlyLinkFlags []string
+	var earlyLinkFlags string
 
 	output.outputFile = outputFile
 	crateName := ctx.RustModule().CrateName()
 	targetTriple := ctx.toolchain().RustTriple()
 
+	envVars := rustEnvVars(ctx, deps)
+
 	inputs = append(inputs, main)
 
 	// Collect rustc flags
@@ -248,6 +286,7 @@
 	// Enable incremental compilation if requested by user
 	if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
 		incrementalPath := android.PathForOutput(ctx, "rustc").String()
+
 		rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath)
 	}
 
@@ -259,16 +298,36 @@
 
 	// Collect linker flags
 	if !ctx.Darwin() {
-		earlyLinkFlags = append(earlyLinkFlags, "-Wl,--as-needed")
+		earlyLinkFlags = "-Wl,--as-needed"
 	}
 
+	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
+	linkFlags = append(linkFlags, flags.LinkFlags...)
+
+	// Check if this module needs to use the bootstrap linker
+	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
+		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
+		if ctx.toolchain().Is64Bit() {
+			dynamicLinker += "64"
+		}
+		linkFlags = append(linkFlags, dynamicLinker)
+	}
+
+	libFlags := makeLibFlags(deps)
+
 	// Collect dependencies
-	var linkImplicits android.Paths
-	implicits := collectImplicits(deps)
-	toolImplicits := android.Concat(deps.BuildToolDeps)
+	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.srcProviderFiles...)
+	implicits = append(implicits, deps.WholeStaticLibs...)
+
+	linkImplicits = append(linkImplicits, deps.LibDeps...)
 	linkImplicits = append(linkImplicits, deps.CrtBegin...)
 	linkImplicits = append(linkImplicits, deps.CrtEnd...)
-	implicits = append(implicits, comp.compilationSourcesAndData(ctx)...)
+
+	linkOrderOnly = append(linkOrderOnly, deps.linkObjects...)
 
 	if len(deps.SrcDeps) > 0 {
 		moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
@@ -283,7 +342,7 @@
 		}
 
 		ctx.Build(pctx, android.BuildParams{
-			Rule:        cpDir,
+			Rule:        cp,
 			Description: "cp " + moduleGenDir.Path().Rel(),
 			Outputs:     outputs,
 			Inputs:      deps.SrcDeps,
@@ -295,183 +354,81 @@
 	}
 
 	if flags.Clippy {
-		clippyRule := getRuleBuilder(ctx, pctx, false, "clippy")
-		clippyCmd := clippyRule.Command()
 		clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
-		clippyDepInfoFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d.raw")
-		clippyDepFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy.d")
-
-		clippyCmd.
-			Flags(rustEnvVars(ctx, deps, clippyCmd)).
-			Tool(config.RustPath(ctx, "bin/clippy-driver")).
-			Flag("--emit metadata").
-			FlagWithOutput("-o ", clippyFile).
-			FlagWithOutput("--emit dep-info=", clippyDepInfoFile).
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, clippyCmd)).
-			Flags(rustcFlags).
-			Flags(flags.ClippyFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-
-		depfileCreationCmd := clippyRule.Command()
-		depfileCreationCmd.
-			Flag(fmt.Sprintf(
-				`grep "^%s:" %s >`,
-				depfileCreationCmd.PathForOutput(clippyFile),
-				depfileCreationCmd.PathForOutput(clippyDepInfoFile),
-			)).
-			DepFile(clippyDepFile)
-
-		clippyRule.BuildWithUnescapedNinjaVars("clippy", "clippy "+main.Rel())
-
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        clippyDriver,
+			Description: "clippy " + main.Rel(),
+			Output:      clippyFile,
+			Inputs:      inputs,
+			Implicits:   implicits,
+			Args: map[string]string{
+				"rustcFlags":  strings.Join(rustcFlags, " "),
+				"libFlags":    strings.Join(libFlags, " "),
+				"clippyFlags": strings.Join(flags.ClippyFlags, " "),
+				"envVars":     strings.Join(envVars, " "),
+			},
+		})
 		// Declare the clippy build as an implicit dependency of the original crate.
 		implicits = append(implicits, clippyFile)
 	}
 
-	sboxDirectory := "rustc"
-	rustSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-	depFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d")
-	depInfoFile := android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".d.raw")
-	var rustcImplicitOutputs android.WritablePaths
-
-	sandboxedCompilation := comp.crateRoot(ctx) != nil
-	rustcRule := getRuleBuilder(ctx, pctx, sandboxedCompilation, sboxDirectory)
-	rustcCmd := rustcRule.Command()
-
-	linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
-	linkFlags = append(linkFlags, flags.LinkFlags...)
-	linkFlags = append(linkFlags, rustcCmd.PathsForInputs(deps.linkObjects)...)
-
-	// Check if this module needs to use the bootstrap linker
-	if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
-		dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
-		if ctx.toolchain().Is64Bit() {
-			dynamicLinker += "64"
-		}
-		linkFlags = append(linkFlags, dynamicLinker)
-	}
-
-	libFlags := makeLibFlags(deps, rustcCmd)
-
+	rustcOutputFile := outputFile
 	usesLinker := crateType == "bin" || crateType == "dylib" || crateType == "cdylib" || crateType == "proc-macro"
 	if usesLinker {
-		rustSboxOutputFile = android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".rsp")
-		rustcImplicitOutputs = android.WritablePaths{
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".whole.a"),
-			android.PathForModuleOut(ctx, sboxDirectory, rustSboxOutputFile.Base()+".a"),
-		}
+		rustcOutputFile = android.PathForModuleOut(ctx, outputFile.Base()+".rsp")
 	}
 
-	clangTools := android.Paths{
-		cc_config.ClangPath(ctx, "bin/llvm-ar"),
-	}
-	if ctx.Config().BuildOS != android.Darwin {
-		clangTools = append(clangTools,
-			cc_config.ClangPath(ctx, "lib/libc++.so"),
-		)
-	}
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustc,
+		Description: "rustc " + main.Rel(),
+		Output:      rustcOutputFile,
+		Inputs:      inputs,
+		Implicits:   implicits,
+		Args: map[string]string{
+			"rustcFlags": strings.Join(rustcFlags, " "),
+			"libFlags":   strings.Join(libFlags, " "),
+			"envVars":    strings.Join(envVars, " "),
+		},
+	})
 
-	rustcCmd.
-		Flags(rustEnvVars(ctx, deps, rustcCmd)).
-		Tool(config.RustPath(ctx, "bin/rustc")).
-		FlagWithInput("-C linker=", android.PathForSource(ctx, "build", "soong", "scripts", "mkcratersp.py")).
-		Flag("--emit link").
-		Flag("-o").
-		Output(rustSboxOutputFile).
-		FlagWithOutput("--emit dep-info=", depInfoFile).
-		Inputs(inputs).
-		Flags(libFlags).
-		Implicits(clangTools).
-		ImplicitTools(toolImplicits).
-		Implicits(implicits).
-		Flags(rustcFlags).
-		ImplicitOutputs(rustcImplicitOutputs)
-
-	depfileCreationCmd := rustcRule.Command()
-	depfileCreationCmd.
-		Flag(fmt.Sprintf(
-			`grep "^%s:" %s >`,
-			depfileCreationCmd.PathForOutput(rustSboxOutputFile),
-			depfileCreationCmd.PathForOutput(depInfoFile),
-		)).
-		DepFile(depFile)
-
-	if !usesLinker {
+	if usesLinker {
 		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  rustSboxOutputFile,
-			Output: outputFile,
-		})
-	} else {
-		// TODO: delmerico - separate rustLink into its own rule
-		// mkcratersp.py hardcodes paths to files within the sandbox, so
-		// those need to be renamed/symlinked to something in the rustLink sandbox
-		// if we want to separate the rules
-		linkerSboxOutputFile := android.PathForModuleOut(ctx, sboxDirectory, outputFile.Base())
-		clangTools := android.Paths{
-			cc_config.ClangPath(ctx, "bin/clang++"),
-			cc_config.ClangPath(ctx, "bin/lld"),
-			cc_config.ClangPath(ctx, "bin/ld.lld"),
-		}
-		if ctx.Config().BuildOS != android.Darwin {
-			clangTools = append(clangTools,
-				cc_config.ClangPath(ctx, "bin/clang++.real"),
-				cc_config.ClangPath(ctx, "lib/libc++.so"),
-			)
-		}
-		rustLinkCmd := rustcRule.Command()
-		rustLinkCmd.
-			Tool(cc_config.ClangPath(ctx, "bin/clang++")).
-			Flag("-o").
-			Output(linkerSboxOutputFile).
-			Inputs(deps.CrtBegin).
-			Flags(earlyLinkFlags).
-			FlagWithInput("@", rustSboxOutputFile).
-			Flags(linkFlags).
-			Inputs(deps.CrtEnd).
-			ImplicitTools(clangTools).
-			ImplicitTools(toolImplicits).
-			Implicits(rustcImplicitOutputs.Paths()).
-			Implicits(implicits).
-			Implicits(linkImplicits)
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   cp,
-			Input:  linkerSboxOutputFile,
-			Output: outputFile,
+			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(), " "),
+			},
 		})
 	}
 
-	rustcRule.BuildWithUnescapedNinjaVars("rustc", "rustc "+main.Rel())
-
 	if flags.EmitXrefs {
-		kytheRule := getRuleBuilder(ctx, pctx, false, "kythe")
-		kytheCmd := kytheRule.Command()
 		kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
-		kytheCmd.
-			Flag("KYTHE_CORPUS=${kytheCorpus}").
-			FlagWithOutput("KYTHE_OUTPUT_FILE=", kytheFile).
-			FlagWithInput("KYTHE_VNAMES=", android.PathForSource(ctx, "build", "soong", "vnames.json")).
-			Flag("KYTHE_KZIP_ENCODING=${kytheCuEncoding}").
-			Flag("KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative").
-			Tool(ctx.Config().PrebuiltBuildTool(ctx, "rust_extractor")).
-			Flags(rustEnvVars(ctx, deps, kytheCmd)).
-			Tool(config.RustPath(ctx, "bin/rustc")).
-			Flag("-C linker=true").
-			Inputs(inputs).
-			Flags(makeLibFlags(deps, kytheCmd)).
-			Flags(rustcFlags).
-			ImplicitTools(toolImplicits).
-			Implicits(implicits)
-		kytheRule.BuildWithUnescapedNinjaVars("kythe", "Xref Rust extractor "+main.Rel())
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        kytheExtract,
+			Description: "Xref Rust extractor " + main.Rel(),
+			Output:      kytheFile,
+			Inputs:      inputs,
+			Implicits:   implicits,
+			Args: map[string]string{
+				"rustcFlags": strings.Join(rustcFlags, " "),
+				"libFlags":   strings.Join(libFlags, " "),
+				"envVars":    strings.Join(envVars, " "),
+			},
+		})
 		output.kytheFile = kytheFile
 	}
 	return output
 }
 
-func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags) android.ModuleOutPath {
-	rustdocRule := getRuleBuilder(ctx, pctx, false, "rustdoc")
-	rustdocCmd := rustdocRule.Command()
+func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps,
+	flags Flags) android.ModuleOutPath {
 
 	rustdocFlags := append([]string{}, flags.RustdocFlags...)
 	rustdocFlags = append(rustdocFlags, "--sysroot=/dev/null")
@@ -490,7 +447,7 @@
 	crateName := ctx.RustModule().CrateName()
 	rustdocFlags = append(rustdocFlags, "--crate-name "+crateName)
 
-	rustdocFlags = append(rustdocFlags, makeLibFlags(deps, rustdocCmd)...)
+	rustdocFlags = append(rustdocFlags, makeLibFlags(deps)...)
 	docTimestampFile := android.PathForModuleOut(ctx, "rustdoc.timestamp")
 
 	// Silence warnings about renamed lints for third-party crates
@@ -506,26 +463,18 @@
 	// https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146
 	docDir := android.PathForOutput(ctx, "rustdoc")
 
-	rustdocCmd.
-		Flags(rustEnvVars(ctx, deps, rustdocCmd)).
-		Tool(config.RustPath(ctx, "bin/rustdoc")).
-		Flags(rustdocFlags).
-		Input(main).
-		Flag("-o "+docDir.String()).
-		FlagWithOutput("&& touch ", docTimestampFile).
-		Implicit(ctx.RustModule().UnstrippedOutputFile())
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        rustdoc,
+		Description: "rustdoc " + main.Rel(),
+		Output:      docTimestampFile,
+		Input:       main,
+		Implicit:    ctx.RustModule().UnstrippedOutputFile(),
+		Args: map[string]string{
+			"rustdocFlags": strings.Join(rustdocFlags, " "),
+			"outDir":       docDir.String(),
+			"envVars":      strings.Join(rustEnvVars(ctx, deps), " "),
+		},
+	})
 
-	rustdocRule.BuildWithUnescapedNinjaVars("rustdoc", "rustdoc "+main.Rel())
 	return docTimestampFile
 }
-
-func getRuleBuilder(ctx android.ModuleContext, pctx android.PackageContext, sbox bool, sboxDirectory string) *android.RuleBuilder {
-	r := android.NewRuleBuilder(pctx, ctx)
-	if sbox {
-		r = r.Sbox(
-			android.PathForModuleOut(ctx, sboxDirectory),
-			android.PathForModuleOut(ctx, sboxDirectory+".sbox.textproto"),
-		).SandboxInputs()
-	}
-	return r
-}
diff --git a/rust/clippy_test.go b/rust/clippy_test.go
index 2703a1c..bd3bfb1 100644
--- a/rust/clippy_test.go
+++ b/rust/clippy_test.go
@@ -63,14 +63,14 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.ClippyDefaultLints}")
+			android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"])
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
 			if r.Rule != nil {
-				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: command=%q", r.RuleParams.Command)
+				t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"])
 			}
 		})
 	}
diff --git a/rust/compiler.go b/rust/compiler.go
index 3fa3ccd..e6a7a93 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -73,18 +73,6 @@
 	// If no source file is defined, a single generated source module can be defined to be used as the main source.
 	Srcs []string `android:"path,arch_variant"`
 
-	// Entry point that is passed to rustc to begin the compilation. E.g. main.rs or lib.rs.
-	// When this property is set,
-	//    * sandboxing is enabled for this module, and
-	//    * the srcs attribute is interpreted as a list of all source files potentially
-	//          used in compilation, including the entrypoint, and
-	//    * compile_data can be used to add additional files used in compilation that
-	//          not directly used as source files.
-	Crate_root *string `android:"path,arch_variant"`
-
-	// Additional data files that are used during compilation only. These are not accessible at runtime.
-	Compile_data []string `android:"path,arch_variant"`
-
 	// name of the lint set that should be used to validate this module.
 	//
 	// Possible values are "default" (for using a sensible set of lints
@@ -346,23 +334,6 @@
 	panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
 }
 
-func (compile *baseCompiler) crateRoot(ctx ModuleContext) android.Path {
-	if compile.Properties.Crate_root != nil {
-		return android.PathForModuleSrc(ctx, *compile.Properties.Crate_root)
-	}
-	return nil
-}
-
-// compilationSourcesAndData returns a list of files necessary to complete the compilation.
-// This includes the rust source files as well as any other data files that
-// are referenced during the build.
-func (compile *baseCompiler) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	return android.PathsForModuleSrc(ctx, android.Concat(
-		compile.Properties.Srcs,
-		compile.Properties.Compile_data,
-	))
-}
-
 func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags,
 	deps PathDeps) android.OptionalPath {
 
@@ -540,8 +511,6 @@
 		ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.")
 	}
 
-	// TODO: b/297264540 - once all modules are sandboxed, we need to select the proper
-	// entry point file from Srcs rather than taking the first one
 	paths := android.PathsForModuleSrc(ctx, srcs)
 	return paths[srcIndex], paths[1:]
 }
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index e5cc888..ec6829a 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -36,9 +36,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"fizz\"'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'feature=\"buzz\"'") {
-		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, command: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") {
+		t.Fatalf("missing fizz and buzz feature flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -57,9 +57,9 @@
 
 	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "cfg 'std'") ||
-		!strings.Contains(libfooDylib.RuleParams.Command, "cfg 'cfg1=\"one\"'") {
-		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") ||
+		!strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") {
+		t.Fatalf("missing std and cfg1 flags for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -146,14 +146,14 @@
 
 	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc")
 
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_BIN_NAME=fizz") {
-		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") {
+		t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_CRATE_NAME=foo") {
-		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_CRATE_NAME=foo") {
+		t.Fatalf("expected 'CARGO_CRATE_NAME=foo' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
-	if !strings.Contains(fizz.RuleParams.Command, "CARGO_PKG_VERSION=1.0.0") {
-		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual command: %#v", fizz.RuleParams.Command)
+	if !strings.Contains(fizz.Args["envVars"], "CARGO_PKG_VERSION=1.0.0") {
+		t.Fatalf("expected 'CARGO_PKG_VERSION=1.0.0' in envVars, actual envVars: %#v", fizz.Args["envVars"])
 	}
 }
 
@@ -230,13 +230,13 @@
 			).RunTest(t)
 
 			r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoo flags", r.RuleParams.Command, tc.fooFlags)
+			android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags)
 
 			r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libbar flags", r.RuleParams.Command, "${config.RustDefaultLints}")
+			android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}")
 
 			r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
-			android.AssertStringDoesContain(t, "libfoobar flags", r.RuleParams.Command, "${config.RustAllowAllLints}")
+			android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}")
 		})
 	}
 }
diff --git a/rust/config/global.go b/rust/config/global.go
index 9daafba..c976617 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -81,7 +81,13 @@
 
 func init() {
 	pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase)
-	pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag)
+	pctx.VariableConfigMethod("HostPrebuiltTag", func(config android.Config) string {
+		if config.UseHostMusl() {
+			return "linux-musl-x86"
+		} else {
+			return config.PrebuiltOS()
+		}
+	})
 
 	pctx.VariableFunc("RustBase", func(ctx android.PackageVarContext) string {
 		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
@@ -103,14 +109,6 @@
 	exportedVars.ExportStringStaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion)
 }
 
-func HostPrebuiltTag(config android.Config) string {
-	if config.UseHostMusl() {
-		return "linux-musl-x86"
-	} else {
-		return config.PrebuiltOS()
-	}
-}
-
 func getRustVersionPctx(ctx android.PackageVarContext) string {
 	return GetRustVersion(ctx)
 }
@@ -126,27 +124,3 @@
 func BazelRustToolchainVars(config android.Config) string {
 	return android.BazelToolchainVars(config, exportedVars)
 }
-
-func RustPath(ctx android.PathContext, file string) android.SourcePath {
-	type rustToolKey string
-	key := android.NewCustomOnceKey(rustToolKey(file))
-	return ctx.Config().OnceSourcePath(key, func() android.SourcePath {
-		return rustPath(ctx).Join(ctx, file)
-	})
-}
-
-var rustPathKey = android.NewOnceKey("clangPath")
-
-func rustPath(ctx android.PathContext) android.SourcePath {
-	return ctx.Config().OnceSourcePath(rustPathKey, func() android.SourcePath {
-		rustBase := RustDefaultBase
-		if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" {
-			rustBase = override
-		}
-		rustVersion := RustDefaultVersion
-		if override := ctx.Config().Getenv("RUST_DEFAULT_VERSION"); override != "" {
-			rustVersion = override
-		}
-		return android.PathForSource(ctx, rustBase, HostPrebuiltTag(ctx.Config()), rustVersion)
-	})
-}
diff --git a/rust/coverage.go b/rust/coverage.go
index b312194..5216d60 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -17,7 +17,6 @@
 import (
 	"github.com/google/blueprint"
 
-	"android/soong/android"
 	"android/soong/cc"
 )
 
@@ -71,10 +70,7 @@
 		// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
 		if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
 			profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module)
-			deps.Rlibs = android.AddDirectToDepSet[RustLibrary](deps.Rlibs, RustLibrary{
-				Path:      profiler_builtins.OutputFile().Path(),
-				CrateName: profiler_builtins.CrateName(),
-			})
+			deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()})
 		}
 
 		if cc.EnableContinuousCoverage(ctx) {
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 1466e0c..64077cf 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -55,27 +55,27 @@
 	libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
 	fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
 	buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
-	libfooCovLink := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc")
-	libbarNoCovLink := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
-	fizzCovLink := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
-	buzzNoCovLink := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
+	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 {
 		missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.RuleParams.Command)
+		if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
 		}
-		if !strings.Contains(libfooCov.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.RuleParams.Command)
+		if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
 		}
-		if strings.Contains(buzzNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.RuleParams.Command)
+		if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
 		}
-		if strings.Contains(libbarNoCov.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.RuleParams.Command)
+		if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
 		}
 	}
 
@@ -84,17 +84,17 @@
 		missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
 		containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
 
-		if !strings.Contains(fizzCovLink.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.RuleParams.Command)
+		if !strings.Contains(fizzCovLink.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCovLink.Args["linkFlags"])
 		}
-		if !strings.Contains(libfooCovLink.RuleParams.Command, flag) {
-			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.RuleParams.Command)
+		if !strings.Contains(libfooCovLink.Args["linkFlags"], flag) {
+			t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCovLink.Args["linkFlags"])
 		}
-		if strings.Contains(buzzNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.RuleParams.Command)
+		if strings.Contains(buzzNoCovLink.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCovLink.Args["linkFlags"])
 		}
-		if strings.Contains(libbarNoCovLink.RuleParams.Command, flag) {
-			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.RuleParams.Command)
+		if strings.Contains(libbarNoCovLink.Args["linkFlags"], flag) {
+			t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCovLink.Args["linkFlags"])
 		}
 	}
 
@@ -107,8 +107,8 @@
 			srcs: ["foo.rs"],
 		}`)
 
-	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
-	if !strings.Contains(fizz.RuleParams.Command, "libprofile-clang-extras.a") {
-		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.RuleParams.Command)
+	fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustLink")
+	if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") {
+		t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
 	}
 }
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index ea35905..ee28c6d 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -51,23 +51,23 @@
 
 	// Check that compiler flags are set appropriately .
 	fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(fuzz_libtest.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(fuzz_libtest.RuleParams.Command, "--cfg fuzzing") {
+	if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that host modules support fuzzing.
 	host_fuzzer := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
-	if !strings.Contains(host_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(host_fuzzer.RuleParams.Command, "--cfg fuzzing") {
+	if !strings.Contains(host_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(host_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
 		t.Errorf("rust_fuzz_host module does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 
 	// Check that dependencies have 'fuzzer' variants produced for them as well.
-	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Rule("rustc")
-	if !strings.Contains(libtest_fuzzer.RuleParams.Command, "-C passes='sancov-module'") ||
-		!strings.Contains(libtest_fuzzer.RuleParams.Command, "--cfg fuzzing") {
-		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing). command: %q", libtest_fuzzer.RuleParams.Command)
+	libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
+	if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+		!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
+		t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
 	}
 }
 
diff --git a/rust/image_test.go b/rust/image_test.go
index 813c5bc..fb4d9c1 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -59,36 +59,36 @@
 
 	vendor := ctx.ModuleForTests("libfoo", "android_vendor.29_arm64_armv8-a_static").Rule("rustc")
 
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if !strings.Contains(vendor.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("missing \"--cfg 'android_vendor'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
-	if strings.Contains(vendor.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.RuleParams.Command)
+	if strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
 	}
 
 	product := ctx.ModuleForTests("libfoo", "android_product.29_arm64_armv8-a_static").Rule("rustc")
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if strings.Contains(product.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
-	if !strings.Contains(product.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.RuleParams.Command)
+	if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 	system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vndk'") {
-		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_vendor'") {
-		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vendor'") {
+		t.Errorf("unexpected \"--cfg 'android_vendor'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
 	}
-	if strings.Contains(system.RuleParams.Command, "--cfg 'android_product'") {
-		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.RuleParams.Command)
+	if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_product'") {
+		t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo system variant, rustcFlags: %#v", product.Args["rustcFlags"])
 	}
 
 }
diff --git a/rust/library.go b/rust/library.go
index 7bb82bc..0357086 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -485,28 +485,11 @@
 	return flags
 }
 
-func (library *libraryDecorator) compilationSourcesAndData(ctx ModuleContext) android.Paths {
-	var extraSrcs android.Paths
-	if library.rlib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Rlib.Srcs)
-	} else if library.dylib() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Dylib.Srcs)
-	} else if library.static() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Static.Srcs)
-	} else if library.shared() {
-		extraSrcs = android.PathsForModuleSrc(ctx, library.Properties.Shared.Srcs)
-	}
-	return android.Concat(
-		library.baseCompiler.compilationSourcesAndData(ctx),
-		extraSrcs,
-	)
-}
-
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
 	var outputFile android.ModuleOutPath
 	var ret buildOutput
 	var fileName string
-	crateRootPath := library.crateRootPath(ctx, deps)
+	srcPath := library.srcPath(ctx, deps)
 
 	if library.sourceProvider != nil {
 		deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
@@ -542,6 +525,7 @@
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects.Strings()...)
 
 	if library.dylib() {
 		// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -552,13 +536,13 @@
 
 	// Call the appropriate builder for this library type
 	if library.rlib() {
-		ret.kytheFile = TransformSrctoRlib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile).kytheFile
 	} else if library.dylib() {
-		ret.kytheFile = TransformSrctoDylib(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile).kytheFile
 	} else if library.static() {
-		ret.kytheFile = TransformSrctoStatic(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile).kytheFile
 	} else if library.shared() {
-		ret.kytheFile = TransformSrctoShared(ctx, library, crateRootPath, deps, flags, outputFile).kytheFile
+		ret.kytheFile = TransformSrctoShared(ctx, srcPath, deps, flags, outputFile).kytheFile
 	}
 
 	if library.rlib() || library.dylib() {
@@ -601,15 +585,13 @@
 	return ret
 }
 
-func (library *libraryDecorator) crateRootPath(ctx ModuleContext, _ PathDeps) android.Path {
+func (library *libraryDecorator) srcPath(ctx ModuleContext, _ PathDeps) android.Path {
 	if library.sourceProvider != nil {
 		// Assume the first source from the source provider is the library entry point.
 		return library.sourceProvider.Srcs()[0]
-	} else if library.baseCompiler.Properties.Crate_root == nil {
+	} else {
 		path, _ := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
 		return path
-	} else {
-		return android.PathForModuleSrc(ctx, *library.baseCompiler.Properties.Crate_root)
 	}
 }
 
@@ -624,7 +606,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(Rustdoc(ctx, library.crateRootPath(ctx, deps),
+	return android.OptionalPathForPath(Rustdoc(ctx, library.srcPath(ctx, deps),
 		deps, flags))
 }
 
diff --git a/rust/library_test.go b/rust/library_test.go
index dab9381..30ef333 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -48,23 +48,23 @@
 	staticCrateType := "staticlib"
 
 	// Test crate type for rlib is correct.
-	if !strings.Contains(libfooRlib.RuleParams.Command, "crate-type="+rlibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.RuleParams.Command)
+	if !strings.Contains(libfooRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooRlib.Args["rustcFlags"])
 	}
 
 	// Test crate type for dylib is correct.
-	if !strings.Contains(libfooDylib.RuleParams.Command, "crate-type="+dylibCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "crate-type="+dylibCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", dylibCrateType, libfooDylib.Args["rustcFlags"])
 	}
 
 	// Test crate type for C static libraries is correct.
-	if !strings.Contains(libfooStatic.RuleParams.Command, "crate-type="+staticCrateType) {
-		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.RuleParams.Command)
+	if !strings.Contains(libfooStatic.Args["rustcFlags"], "crate-type="+staticCrateType) {
+		t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
 	}
 
 	// Test crate type for C shared libraries is correct.
-	if !strings.Contains(libfooShared.RuleParams.Command, "crate-type="+sharedCrateType) {
-		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.RuleParams.Command)
+	if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
+		t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
 	}
 
 }
@@ -78,10 +78,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "prefer-dynamic") {
-		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") {
+		t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -94,10 +94,10 @@
 			crate_name: "foo",
 		}`)
 
-	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Description("rustc")
+	libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
 
-	if !strings.Contains(libfooDylib.RuleParams.Command, "--cfg 'android_dylib'") {
-		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.RuleParams.Command)
+	if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") {
+		t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"])
 	}
 }
 
@@ -148,10 +148,10 @@
 
 	libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
 
-	libfooOutput := libfoo.Rule("rustc")
-	if !strings.Contains(libfooOutput.RuleParams.Command, "-Wl,-soname=libfoo.so") {
+	libfooOutput := libfoo.Rule("rustLink")
+	if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
 		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
-			libfooOutput.RuleParams.Command)
+			libfooOutput.Args["linkFlags"])
 	}
 
 	if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
@@ -237,21 +237,19 @@
 	// The build system assumes the  cc deps will be at the final linkage (either a shared library or binary)
 	// Hence, these flags are no-op
 	// TODO: We could consider removing these flags
-	expectedSharedFlag := "-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared"
-	expectedStaticFlag := "-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static"
 	for _, module := range modules {
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedSharedFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/shared_cc_dep/android_arm64_armv8-a_shared/") {
 			t.Errorf(
-				"expected to find shared library linkdir flag %q, rustcFlags: %#v",
-				expectedSharedFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for shared_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
-		if !strings.Contains(module.Rule("rustc").RuleParams.Command, expectedStaticFlag) {
+		if !strings.Contains(module.Rule("rustc").Args["libFlags"],
+			"-L out/soong/.intermediates/static_cc_dep/android_arm64_armv8-a_static/") {
 			t.Errorf(
-				"expected to find static library linkdir flag %q, rustcFlags: %#v",
-				expectedStaticFlag,
-				rustRlibRlibStd.Rule("rustc").RuleParams.Command,
+				"missing -L flag for static_cc_dep, rustcFlags: %#v",
+				rustRlibRlibStd.Rule("rustc").Args["libFlags"],
 			)
 		}
 	}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index d012680..fe9d0b5 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -146,10 +146,7 @@
 }
 
 func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	deps.linkDirs = append(deps.linkDirs, android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
-	prebuilt.flagExporter.exportLinkDirs(deps.linkDirs...)
-	prebuilt.flagExporter.exportLinkObjects(deps.linkObjects...)
-	prebuilt.flagExporter.exportLibDeps(deps.LibDeps...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
@@ -206,7 +203,7 @@
 }
 
 func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput {
-	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs)...)
+	prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
 	prebuilt.flagExporter.setProvider(ctx)
 
 	srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 3f0d17a..b93b24f 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -80,7 +80,7 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
-	ret := TransformSrctoProcMacro(ctx, procMacro, srcPath, deps, flags, outputFile)
+	ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
 	procMacro.baseCompiler.unstrippedOutputFile = outputFile
 	return ret
 }
diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go
index a547926..cc81938 100644
--- a/rust/proc_macro_test.go
+++ b/rust/proc_macro_test.go
@@ -30,7 +30,7 @@
 
 	libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(libprocmacro.RuleParams.Command, "--extern proc_macro") {
-		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.RuleParams.Command)
+	if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") {
+		t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"])
 	}
 }
diff --git a/rust/rust.go b/rust/rust.go
index 26e3ffc..3b24484 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -438,18 +438,12 @@
 }
 
 type PathDeps struct {
-	Dylibs          *android.DepSet[RustLibrary]
-	Rlibs           *android.DepSet[RustLibrary]
-	ProcMacros      *android.DepSet[RustLibrary]
+	DyLibs          RustLibraries
+	RLibs           RustLibraries
 	LibDeps         android.Paths
 	WholeStaticLibs android.Paths
+	ProcMacros      RustLibraries
 	AfdoProfiles    android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/tools/...
-	BuildToolDeps android.Paths
-	// These paths are files needed to run the build tools and will be located under
-	// __SBOX_SANDBOX_DIR__/...
-	BuildToolSrcDeps android.Paths
 
 	// depFlags and depLinkFlags are rustc and linker (clang) flags.
 	depFlags     []string
@@ -457,7 +451,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    android.Paths
+	linkDirs    []string
 	linkObjects android.Paths
 
 	// Used by bindgen modules which call clang
@@ -491,8 +485,6 @@
 	compilerDeps(ctx DepsContext, deps Deps) Deps
 	crateName() string
 	rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
-	crateRoot(ctx ModuleContext) android.Path
-	compilationSourcesAndData(ctx ModuleContext) android.Paths
 
 	// Output directory in which source-generated code from dependencies is
 	// copied. This is equivalent to Cargo's OUT_DIR variable.
@@ -522,7 +514,7 @@
 }
 
 type exportedFlagsProducer interface {
-	exportLinkDirs(...android.Path)
+	exportLinkDirs(...string)
 	exportLinkObjects(...android.Path)
 }
 
@@ -531,13 +523,13 @@
 }
 
 type flagExporter struct {
-	linkDirs    android.Paths
+	linkDirs    []string
 	linkObjects android.Paths
 	libDeps     android.Paths
 }
 
-func (flagExporter *flagExporter) exportLinkDirs(dirs ...android.Path) {
-	flagExporter.linkDirs = android.FirstUniquePaths(append(flagExporter.linkDirs, dirs...))
+func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
+	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
 
 func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
@@ -564,7 +556,7 @@
 
 type FlagExporterInfo struct {
 	Flags       []string
-	LinkDirs    android.Paths
+	LinkDirs    []string // TODO: this should be android.Paths
 	LinkObjects android.Paths
 	LibDeps     android.Paths
 }
@@ -934,14 +926,6 @@
 func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 }
 
-type RustInfo struct {
-	TransitiveRlibs      *android.DepSet[RustLibrary]
-	TransitiveDylibs     *android.DepSet[RustLibrary]
-	TransitiveProcMacros *android.DepSet[RustLibrary]
-}
-
-var RustInfoProvider = blueprint.NewProvider(RustInfo{})
-
 func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
 	ctx := &moduleContext{
 		ModuleContext: actx,
@@ -1051,12 +1035,6 @@
 
 		ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
 	}
-
-	ctx.SetProvider(RustInfoProvider, RustInfo{
-		TransitiveRlibs:      deps.Rlibs,
-		TransitiveDylibs:     deps.Dylibs,
-		TransitiveProcMacros: deps.ProcMacros,
-	})
 }
 
 func (mod *Module) deps(ctx DepsContext) Deps {
@@ -1115,7 +1093,6 @@
 var _ android.LicenseAnnotationsDependencyTag = dependencyTag{}
 
 var (
-	buildToolDepTag     = dependencyTag{name: "buildToolTag"}
 	customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
 	rlibDepTag          = dependencyTag{name: "rlibTag", library: true}
 	dylibDepTag         = dependencyTag{name: "dylib", library: true, dynamic: true}
@@ -1249,9 +1226,7 @@
 
 	var transitiveAndroidMkSharedLibs []*android.DepSet[string]
 	var directAndroidMkSharedLibs []string
-	transitiveRlibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveDylibs := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
-	transitiveProcMacros := android.NewDepSetBuilder[RustLibrary](android.PREORDER)
+
 	ctx.VisitDirectDeps(func(dep android.Module) {
 		depName := ctx.OtherModuleName(dep)
 		depTag := ctx.OtherModuleDependencyTag(dep)
@@ -1264,17 +1239,6 @@
 			return
 		}
 
-		rustInfo := ctx.OtherModuleProvider(dep, RustInfoProvider).(RustInfo)
-		if rustInfo.TransitiveDylibs != nil {
-			transitiveDylibs.Transitive(rustInfo.TransitiveDylibs)
-		}
-		if rustInfo.TransitiveRlibs != nil {
-			transitiveRlibs.Transitive(rustInfo.TransitiveRlibs)
-		}
-		if rustInfo.TransitiveProcMacros != nil {
-			transitiveProcMacros.Transitive(rustInfo.TransitiveProcMacros)
-		}
-
 		if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
 			//Handle Rust Modules
 			makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1289,12 +1253,9 @@
 				directDylibDeps = append(directDylibDeps, rustDep)
 				mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName)
 				mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName))
-				transitiveDylibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case rlibDepTag:
+
 				rlib, ok := rustDep.compiler.(libraryInterface)
 				if !ok || !rlib.rlib() {
 					ctx.ModuleErrorf("mod %q not an rlib library", makeLibName)
@@ -1303,18 +1264,10 @@
 				directRlibDeps = append(directRlibDeps, rustDep)
 				mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
 				mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
-				transitiveRlibs.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 
 			case procMacroDepTag:
 				directProcMacroDeps = append(directProcMacroDeps, rustDep)
 				mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
-				transitiveProcMacros.Direct(RustLibrary{
-					Path:      rustDep.UnstrippedOutputFile(),
-					CrateName: rustDep.CrateName(),
-				})
 			}
 
 			transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs)
@@ -1350,8 +1303,9 @@
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
 				linkFile := rustDep.UnstrippedOutputFile()
+				linkDir := linkPathFromFilePath(linkFile)
 				if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
-					lib.exportLinkDirs(linkFile.Dir())
+					lib.exportLinkDirs(linkDir)
 				}
 			}
 
@@ -1378,7 +1332,7 @@
 				return
 			}
 
-			linkPath := linkObject.Path().Dir()
+			linkPath := linkPathFromFilePath(linkObject.Path())
 
 			exportDep := false
 			switch {
@@ -1432,7 +1386,7 @@
 					}
 					return
 				}
-				linkPath = linkObject.Path().Dir()
+				linkPath = linkPathFromFilePath(linkObject.Path())
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
@@ -1467,16 +1421,6 @@
 			}
 		} else {
 			switch {
-			case depTag == buildToolDepTag:
-				buildTool := ctx.OtherModuleProvider(dep, android.PrebuiltBuildToolInfoProvider).(android.PrebuiltBuildToolInfo)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Src)
-				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Deps...)
-				switch android.RemoveOptionalPrebuiltPrefix(dep.Name()) {
-				case "rustc":
-					// rustc expects the standard cc toolchain libraries (libdl, libm, libc, etc.)
-					// not to be under the __SBOX_SANDBOX_DIR__/ directory
-					depPaths.BuildToolSrcDeps = append(depPaths.BuildToolSrcDeps, buildTool.Deps...)
-				}
 			case depTag == cc.CrtBeginDepTag:
 				depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, ""))
 			case depTag == cc.CrtEndDepTag:
@@ -1492,6 +1436,21 @@
 		}
 	})
 
+	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
+
+	var rlibDepFiles RustLibraries
+	for _, dep := range directRlibDeps {
+		rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+	var dylibDepFiles RustLibraries
+	for _, dep := range directDylibDeps {
+		dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+	var procMacroDepFiles RustLibraries
+	for _, dep := range directProcMacroDeps {
+		procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: dep.CrateName()})
+	}
+
 	var libDepFiles android.Paths
 	for _, dep := range directStaticLibDeps {
 		libDepFiles = append(libDepFiles, dep.OutputFile().Path())
@@ -1515,22 +1474,20 @@
 		srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
 	}
 
+	depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
+	depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
 	depPaths.LibDeps = append(depPaths.LibDeps, libDepFiles...)
+	depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
 	depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
 
 	// Dedup exported flags from dependencies
-	depPaths.linkDirs = android.FirstUniquePaths(depPaths.linkDirs)
+	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
 	depPaths.linkObjects = android.FirstUniquePaths(depPaths.linkObjects)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
 	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
 	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
 	depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
 
-	depPaths.Rlibs = transitiveRlibs.Build()
-	depPaths.Dylibs = transitiveDylibs.Build()
-	depPaths.ProcMacros = transitiveProcMacros.Build()
-	mod.transitiveAndroidMkSharedLibs = android.NewDepSet[string](android.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs)
-
 	return depPaths
 }
 
@@ -1553,6 +1510,10 @@
 	return mod.InRecovery()
 }
 
+func linkPathFromFilePath(filepath android.Path) string {
+	return strings.Split(filepath.String(), filepath.Base())[0]
+}
+
 // usePublicApi returns true if the rust variant should link against NDK (publicapi)
 func (r *Module) usePublicApi() bool {
 	return r.Device() && r.UseSdk()
@@ -1595,8 +1556,6 @@
 			blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
 	}
 
-	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustc")
-
 	// rlibs
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 576209d..835114c 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -15,17 +15,14 @@
 package rust
 
 import (
-	"fmt"
 	"os"
 	"runtime"
 	"strings"
 	"testing"
 
 	"github.com/google/blueprint/proptools"
-	"google.golang.org/protobuf/encoding/prototext"
 
 	"android/soong/android"
-	"android/soong/cmd/sbox/sbox_proto"
 	"android/soong/genrule"
 )
 
@@ -67,14 +64,11 @@
 
 // testRust returns a TestContext in which a basic environment has been setup.
 // This environment contains a few mocked files. See rustMockedFiles for the list of these files.
-func testRust(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext {
+func testRust(t *testing.T, bp string) *android.TestContext {
 	skipTestIfOsNotSupported(t)
 	result := android.GroupFixturePreparers(
 		prepareForRustTest,
 		rustMockedFiles.AddToFixture(),
-		android.GroupFixturePreparers(
-			preparers...,
-		),
 	).
 		RunTestWithBp(t, bp)
 	return result.TestContext
@@ -208,11 +202,11 @@
 // Test that we can extract the link path from a lib path.
 func TestLinkPathFromFilePath(t *testing.T) {
 	barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
-	libName := barPath.Dir()
-	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared"
+	libName := linkPathFromFilePath(barPath)
+	expectedResult := "out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/"
 
-	if libName.String() != expectedResult {
-		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName.String())
+	if libName != expectedResult {
+		t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libName)
 	}
 }
 
@@ -262,7 +256,7 @@
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
 	rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
-	rustLink := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc")
+	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) {
@@ -281,16 +275,16 @@
 		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
 	}
 
-	if !strings.Contains(rustc.RuleParams.Command, "-lstatic=wholestatic") {
-		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.RuleParams.Command)
+	if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") {
+		t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"])
 	}
 
-	if !strings.Contains(rustLink.RuleParams.Command, "cc_stubs_dep.so") {
-		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.RuleParams.Command)
+	if !strings.Contains(rustLink.Args["linkFlags"], "cc_stubs_dep.so") {
+		t.Errorf("shared cc_library not being passed to rustc linkFlags %#v", rustLink.Args["linkFlags"])
 	}
 
-	if !android.SuffixInList(rustLink.Implicits.Strings(), "cc_stubs_dep.so") {
-		t.Errorf("shared cc dep not being passed as implicit to rustc %#v", rustLink.OrderOnly.Strings())
+	if !android.SuffixInList(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(rustLink.Implicits.Strings(), "cc_stubs_dep.so.toc") {
@@ -433,7 +427,7 @@
 	`)
 	rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc")
 
-	if !strings.Contains(rustc.RuleParams.Command, "libbar/linux_glibc_x86_64") {
+	if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") {
 		t.Errorf("Proc_macro is not using host variant of dependent modules.")
 	}
 }
@@ -486,396 +480,3 @@
 		t.Errorf("expected %q got %q", expected, got)
 	}
 }
-
-var (
-	sboxCompilationFiles = []string{
-		"out/soong/.intermediates/defaults/rust/libaddr2line/android_arm64_armv8-a_rlib/libaddr2line.rlib",
-		"out/soong/.intermediates/defaults/rust/libadler/android_arm64_armv8-a_rlib/libadler.rlib",
-		"out/soong/.intermediates/defaults/rust/liballoc/android_arm64_armv8-a_rlib/liballoc.rlib",
-		"out/soong/.intermediates/defaults/rust/libcfg_if/android_arm64_armv8-a_rlib/libcfg_if.rlib",
-		"out/soong/.intermediates/defaults/rust/libcompiler_builtins/android_arm64_armv8-a_rlib/libcompiler_builtins.rlib",
-		"out/soong/.intermediates/defaults/rust/libcore/android_arm64_armv8-a_rlib/libcore.rlib",
-		"out/soong/.intermediates/defaults/rust/libgimli/android_arm64_armv8-a_rlib/libgimli.rlib",
-		"out/soong/.intermediates/defaults/rust/libhashbrown/android_arm64_armv8-a_rlib/libhashbrown.rlib",
-		"out/soong/.intermediates/defaults/rust/liblibc/android_arm64_armv8-a_rlib/liblibc.rlib",
-		"out/soong/.intermediates/defaults/rust/libmemchr/android_arm64_armv8-a_rlib/libmemchr.rlib",
-		"out/soong/.intermediates/defaults/rust/libminiz_oxide/android_arm64_armv8-a_rlib/libminiz_oxide.rlib",
-		"out/soong/.intermediates/defaults/rust/libobject/android_arm64_armv8-a_rlib/libobject.rlib",
-		"out/soong/.intermediates/defaults/rust/libpanic_unwind/android_arm64_armv8-a_rlib/libpanic_unwind.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_demangle/android_arm64_armv8-a_rlib/librustc_demangle.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_alloc/android_arm64_armv8-a_rlib/librustc_std_workspace_alloc.rlib",
-		"out/soong/.intermediates/defaults/rust/librustc_std_workspace_core/android_arm64_armv8-a_rlib/librustc_std_workspace_core.rlib",
-		"out/soong/.intermediates/defaults/rust/libstd_detect/android_arm64_armv8-a_rlib/libstd_detect.rlib",
-		"build/soong/scripts/mkcratersp.py",
-		"defaults/rust/linux-x86/1.69.0/bin/rustc",
-		"defaults/rust/linux-x86/1.69.0/lib/libstd.so",
-		"defaults/rust/linux-x86/1.69.0/lib64/libc++.so.1",
-	}
-	sboxCompilationFilesWithCc = []string{
-		"defaults/cc/common",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-		"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-		"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-		"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so",
-		"out/soong/.intermediates/defaults/rust/liblog/android_arm64_armv8-a_shared/liblog.so.toc",
-	}
-)
-
-func TestSandboxCompilation(t *testing.T) {
-	ctx := testRust(t, `
-		filegroup {
-			name: "libsrcs1",
-			srcs: ["src_filegroup1.rs"],
-		}
-		filegroup {
-			name: "libsrcs2",
-			srcs: ["src_filegroup2.rs"],
-		}
-		rust_library {
-			name: "libfizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-			compile_data: [
-				"compile_data1.txt",
-				"compile_data2.txt",
-			],
-			dylib: {
-				srcs: ["dylib_only.rs"],
-			},
-			rlib: {
-				srcs: ["rlib_only.rs"],
-			},
-		}
-		rust_binary {
-			name: "fizz_buzz",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: [
-				"src_lib*.rs",
-				":libsrcs1",
-				":libsrcs2",
-			],
-		}
-		rust_ffi {
-			name: "librust_ffi",
-			crate_name: "rust_ffi",
-			crate_root: "foo.rs",
-			static: {
-				srcs: ["static_only.rs"],
-			},
-			shared: {
-				srcs: ["shared_only.rs"],
-			},
-			srcs: ["src1.rs"],
-		}
-		cc_library_static {
-			name: "cc_dep_static",
-		}
-		cc_library_shared {
-			name: "cc_dep_shared",
-		}
-		rust_library {
-			name: "libfizz_buzz_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			shared_libs: ["cc_dep_shared"],
-			static_libs: ["cc_dep_static"],
-		}
-		rust_library {
-			name: "libfizz_buzz_intermediate_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_cc_deps"],
-		}
-		rust_library {
-			name: "libfizz_buzz_transitive_cc_deps",
-			crate_name:"fizz_buzz",
-			crate_root: "foo.rs",
-			srcs: ["src*.rs"],
-			rustlibs: ["libfizz_buzz_intermediate_cc_deps"],
-		}
-	`,
-		android.FixtureMergeMockFs(android.MockFS{
-			"src_lib1.rs":       nil,
-			"src_lib2.rs":       nil,
-			"src_lib3.rs":       nil,
-			"src_lib4.rs":       nil,
-			"src_filegroup1.rs": nil,
-			"src_filegroup2.rs": nil,
-			"static_only.rs":    nil,
-			"shared_only.rs":    nil,
-		}),
-	)
-
-	testcases := []struct {
-		name                     string
-		moduleName               string
-		variant                  string
-		rustcExpectedFilesToCopy []string
-		expectedFlags            []string
-	}{
-		{
-			name:       "rust_library (dylib)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"compile_data1.txt",
-				"compile_data2.txt",
-				"dylib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so",
-				"out/soong/.intermediates/defaults/cc/common/libc/android_arm64_armv8-a_shared/libc.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so",
-				"out/soong/.intermediates/defaults/cc/common/libm/android_arm64_armv8-a_shared/libm.so.toc",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so",
-				"out/soong/.intermediates/defaults/cc/common/libdl/android_arm64_armv8-a_shared/libdl.so.toc",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy",
-			}),
-			expectedFlags: []string{
-				"-C linker=build/soong/scripts/mkcratersp.py",
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.rsp",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.dylib.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib dylib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_dylib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library (rlib rlib-std)",
-			moduleName: "libfizz_buzz",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"rlib_only.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup1.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/out/src_filegroup2.rs",
-				"out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_rlib_rlib-std/libfizz_buzz.rlib.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/libfizz_buzz.rlib.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_binary",
-			moduleName: "fizz_buzz",
-			variant:    "android_arm64_armv8-a",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src_lib1.rs",
-				"src_lib2.rs",
-				"src_lib3.rs",
-				"src_lib4.rs",
-				"src_filegroup1.rs",
-				"src_filegroup2.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup1.rs",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/out/src_filegroup2.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_dynamic/android_arm64_armv8-a/crtbegin_dynamic.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_android/android_arm64_armv8-a/crtend_android.o",
-				"out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/fizz_buzz",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/fizz_buzz.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi static lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_static",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, []string{
-				"foo.rs",
-				"src1.rs",
-				"static_only.rs",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_static/librust_ffi.a.clippy",
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_rlib/libstd.rlib",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.a",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.a.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_ffi shared lib variant",
-			moduleName: "librust_ffi",
-			variant:    "android_arm64_armv8-a_shared",
-			rustcExpectedFilesToCopy: android.Concat(sboxCompilationFiles, sboxCompilationFilesWithCc, []string{
-				"foo.rs",
-				"src1.rs",
-				"shared_only.rs",
-
-				"out/soong/.intermediates/defaults/rust/libstd/android_arm64_armv8-a_dylib/unstripped/libstd.dylib.so",
-				"out/soong/.intermediates/defaults/cc/common/crtbegin_so/android_arm64_armv8-a/crtbegin_so.o",
-				"out/soong/.intermediates/defaults/cc/common/crtend_so/android_arm64_armv8-a/crtend_so.o",
-				"out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/librust_ffi.so.clippy",
-			}),
-			expectedFlags: []string{
-				"--emit link",
-				"-o __SBOX_SANDBOX_DIR__/out/librust_ffi.so",
-				"--emit dep-info=__SBOX_SANDBOX_DIR__/out/librust_ffi.so.d.raw",
-				"foo.rs", // this is the entry point
-			},
-		},
-		{
-			name:       "rust_library with cc deps (dylib)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (dylib)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_dylib",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib rlib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_rlib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-		{
-			name:       "rust_library with transitive cc deps (rlib dylib-std)",
-			moduleName: "libfizz_buzz_transitive_cc_deps",
-			variant:    "android_arm64_armv8-a_rlib_dylib-std",
-			rustcExpectedFilesToCopy: []string{
-				"out/soong/.intermediates/cc_dep_static/android_arm64_armv8-a_static/cc_dep_static.a",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so",
-				"out/soong/.intermediates/cc_dep_shared/android_arm64_armv8-a_shared/cc_dep_shared.so.toc",
-			},
-		},
-	}
-
-	for _, tc := range testcases {
-		t.Run(tc.name, func(t *testing.T) {
-			writeFile := ctx.ModuleForTests(tc.moduleName, tc.variant).Rule("unescapedWriteFile")
-			contents := writeFile.BuildParams.Args["content"]
-			manifestProto := sbox_proto.Manifest{}
-			err := prototext.Unmarshal([]byte(contents), &manifestProto)
-			if err != nil {
-				t.Errorf("expected no errors unmarshaling manifest proto; got %v", err)
-			}
-
-			if len(manifestProto.Commands) != 1 {
-				t.Errorf("expected 1 command; got %v", len(manifestProto.Commands))
-			}
-
-			// check that sandbox contains correct files
-			rustc := manifestProto.Commands[0]
-			actualFilesToCopy := []string{}
-			for _, copy := range rustc.CopyBefore {
-				actualFilesToCopy = append(actualFilesToCopy, copy.GetFrom())
-			}
-			_, expectedFilesNotCopied, _ := android.ListSetDifference(tc.rustcExpectedFilesToCopy, actualFilesToCopy)
-			if len(expectedFilesNotCopied) > 0 {
-				t.Errorf("did not copy expected files to sbox: %v;\n files copied: %v", expectedFilesNotCopied, actualFilesToCopy)
-			}
-
-			rustcCmd := proptools.String(rustc.Command)
-			for _, flag := range tc.expectedFlags {
-				android.AssertStringDoesContain(
-					t,
-					fmt.Sprintf(
-						"missing flag in rustc invocation; expected to find substring %q; got %q",
-						flag,
-						rustcCmd,
-					),
-					rustcCmd,
-					flag,
-				)
-			}
-		})
-	}
-}
diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go
index d6a14b2..43e95f4 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("rustc").Implicits
+	implicits := m.Rule("rustLink").Implicits
 	for _, lib := range implicits {
 		if strings.Contains(lib.Rel(), note_async) {
 			found = Async
diff --git a/rust/testing.go b/rust/testing.go
index 9951937..3fe751e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -52,22 +52,6 @@
 
 func GatherRequiredDepsForTest() string {
 	bp := `
-		prebuilt_build_tool {
-			name: "rustc",
-			src: "linux-x86/1.69.0/bin/rustc",
-			deps: [
-				"linux-x86/1.69.0/lib/libstd.so",
-				"linux-x86/1.69.0/lib64/libc++.so.1",
-			],
-		}
-		prebuilt_build_tool {
-			name: "clippy-driver",
-			src: "linux-x86/1.69.0/bin/clippy-driver",
-		}
-		prebuilt_build_tool {
-			name: "rustdoc",
-			src: "linux-x86/1.69.0/bin/rustdoc",
-		}
 		rust_prebuilt_library {
 				name: "libstd",
 				crate_name: "std",
@@ -79,25 +63,6 @@
 				},
 				host_supported: true,
 				sysroot: true,
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		//////////////////////////////
 		// Device module requirements
@@ -134,278 +99,6 @@
 			nocrt: true,
 			system_shared_libs: [],
 		}
-		rust_library_rlib {
-			name: "libaddr2line",
-			crate_name: "addr2line",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libadler",
-			crate_name: "adler",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liballoc",
-			crate_name: "alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcfg_if",
-			crate_name: "cfg_if",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcompiler_builtins",
-			crate_name: "compiler_builtins",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libcore",
-			crate_name: "core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libgimli",
-			crate_name: "gimli",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libhashbrown",
-			crate_name: "hashbrown",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "liblibc",
-			crate_name: "libc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libmemchr",
-			crate_name: "memchr",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libminiz_oxide",
-			crate_name: "miniz_oxide",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libobject",
-			crate_name: "object",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libpanic_unwind",
-			crate_name: "panic_unwind",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_demangle",
-			crate_name: "rustc_demangle",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_alloc",
-			crate_name: "rustc_std_workspace_alloc",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "librustc_std_workspace_core",
-			crate_name: "rustc_std_workspace_core",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
-		rust_library_rlib {
-			name: "libstd_detect",
-			crate_name: "std_detect",
-			enabled:true,
-			srcs: ["foo.rs"],
-			no_stdlibs: true,
-			product_available: true,
-			host_supported: true,
-			vendor_available: true,
-			vendor_ramdisk_available: true,
-			recovery_available: true,
-			native_coverage: false,
-			sysroot: true,
-			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
-			min_sdk_version: "29",
-		}
 		rust_library {
 			name: "libstd",
 			crate_name: "std",
@@ -420,25 +113,6 @@
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
 			min_sdk_version: "29",
-			rlibs: [
-			    "libaddr2line",
-			    "libadler",
-			    "liballoc",
-			    "libcfg_if",
-			    "libcompiler_builtins",
-			    "libcore",
-			    "libgimli",
-			    "libhashbrown",
-			    "liblibc",
-			    "libmemchr",
-			    "libminiz_oxide",
-			    "libobject",
-			    "libpanic_unwind",
-			    "librustc_demangle",
-			    "librustc_std_workspace_alloc",
-			    "librustc_std_workspace_core",
-			    "libstd_detect",
-			],
 		}
 		rust_library {
 			name: "libtest",
diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go
index 054104c..326d529 100644
--- a/rust/toolchain_library.go
+++ b/rust/toolchain_library.go
@@ -18,12 +18,9 @@
 
 import (
 	"path"
-	"path/filepath"
 
 	"android/soong/android"
 	"android/soong/rust/config"
-
-	"github.com/google/blueprint/proptools"
 )
 
 // This module is used to compile the rust toolchain libraries
@@ -36,15 +33,11 @@
 		rustToolchainLibraryRlibFactory)
 	android.RegisterModuleType("rust_toolchain_library_dylib",
 		rustToolchainLibraryDylibFactory)
-	android.RegisterModuleType("rust_toolchain_rustc_prebuilt",
-		rustToolchainRustcPrebuiltFactory)
 }
 
 type toolchainLibraryProperties struct {
-	// path to the toolchain crate root, relative to the top of the toolchain source
-	Toolchain_crate_root *string `android:"arch_variant"`
-	// path to the rest of the toolchain srcs, relative to the top of the toolchain source
-	Toolchain_srcs []string `android:"arch_variant"`
+	// path to the toolchain source, relative to the top of the toolchain source
+	Toolchain_src *string `android:"arch_variant"`
 }
 
 type toolchainLibraryDecorator struct {
@@ -89,21 +82,16 @@
 
 func rustSetToolchainSource(ctx android.LoadHookContext) {
 	if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok {
-		prefix := filepath.Join("linux-x86", GetRustPrebuiltVersion(ctx))
-		versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root))
-		versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs))
-		for i, src := range toolchainLib.Properties.Toolchain_srcs {
-			versionedSrcs[i] = path.Join(prefix, src)
-		}
+		prefix := "linux-x86/" + GetRustPrebuiltVersion(ctx)
+		newSrcs := []string{path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_src))}
 
 		type props struct {
-			Crate_root *string
-			Srcs       []string
+			Srcs []string
 		}
 		p := &props{}
-		p.Crate_root = &versionedCrateRoot
-		p.Srcs = versionedSrcs
+		p.Srcs = newSrcs
 		ctx.AppendProperties(p)
+
 	} else {
 		ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.")
 	}
@@ -113,47 +101,3 @@
 func GetRustPrebuiltVersion(ctx android.LoadHookContext) string {
 	return ctx.AConfig().GetenvWithDefault("RUST_PREBUILTS_VERSION", config.RustDefaultVersion)
 }
-
-type toolchainRustcPrebuiltProperties struct {
-	// path to rustc prebuilt, relative to the top of the toolchain source
-	Toolchain_prebuilt_src *string
-	// path to deps, relative to the top of the toolchain source
-	Toolchain_deps []string
-	// path to deps, relative to module directory
-	Deps []string
-}
-
-func rustToolchainRustcPrebuiltFactory() android.Module {
-	module := android.NewPrebuiltBuildTool()
-	module.AddProperties(&toolchainRustcPrebuiltProperties{})
-	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
-		var toolchainProps *toolchainRustcPrebuiltProperties
-		for _, p := range ctx.Module().GetProperties() {
-			toolchainProperties, ok := p.(*toolchainRustcPrebuiltProperties)
-			if ok {
-				toolchainProps = toolchainProperties
-			}
-		}
-
-		if toolchainProps.Toolchain_prebuilt_src == nil {
-			ctx.PropertyErrorf("toolchain_prebuilt_src", "must set path to rustc prebuilt")
-		}
-
-		prefix := filepath.Join(config.HostPrebuiltTag(ctx.Config()), GetRustPrebuiltVersion(ctx))
-		deps := make([]string, 0, len(toolchainProps.Toolchain_deps)+len(toolchainProps.Deps))
-		for _, d := range toolchainProps.Toolchain_deps {
-			deps = append(deps, path.Join(prefix, d))
-		}
-		deps = append(deps, toolchainProps.Deps...)
-
-		props := struct {
-			Src  *string
-			Deps []string
-		}{
-			Src:  proptools.StringPtr(path.Join(prefix, *toolchainProps.Toolchain_prebuilt_src)),
-			Deps: deps,
-		}
-		ctx.AppendProperties(&props)
-	})
-	return module
-}
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 621a724..1e7e7d3 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -1051,7 +1051,7 @@
 	ctx := testRustVndkFsVersions(t, "", mockFS, "30", "current", "31")
 
 	// libclient uses libvndk.vndk.30.arm64, libvendor.vendor_static.30.arm64, libvendor_without_snapshot
-	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustc").RuleParams.Command
+	libclientLdFlags := ctx.ModuleForTests("libclient", sharedVariant).Rule("rustLink").Args["linkFlags"]
 	for _, input := range [][]string{
 		[]string{sharedVariant, "libvndk.vndk.30.arm64"},
 		[]string{staticVariant, "libvendor.vendor_static.30.arm64"},
@@ -1119,7 +1119,7 @@
 		t.Errorf("Unexpected rust rlib name in AndroidMk: %q, expected: %q\n", rustVendorBinMkDylibName, expectedRustVendorSnapshotName)
 	}
 
-	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustc").RuleParams.Command
+	binWithoutSnapshotLdFlags := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("rustLink").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",