support sandboxed rust rules

This commit adds support for compiling rust rules inside the sbox
sandbox. To compile a rust module with sandboxing enabled, the entry
point to the crate must be specified via the `crate_root` property, and
all input sources and compile-time data must be specified via the `srcs`
and `compile_data` properties.

Bug: 286077158
Change-Id: I8c9dc5cf7578037a583b4be2e2f73cf20ffd4408
diff --git a/rust/rust.go b/rust/rust.go
index 1ee99cd..a3bc510 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -437,12 +437,18 @@
 }
 
 type PathDeps struct {
-	DyLibs          RustLibraries
-	RLibs           RustLibraries
+	Dylibs          *android.DepSet[RustLibrary]
+	Rlibs           *android.DepSet[RustLibrary]
+	ProcMacros      *android.DepSet[RustLibrary]
 	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
@@ -450,7 +456,7 @@
 
 	// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
 	// Both of these are exported and propagate to dependencies.
-	linkDirs    []string
+	linkDirs    android.Paths
 	linkObjects android.Paths
 
 	// Used by bindgen modules which call clang
@@ -465,6 +471,13 @@
 	// Paths to generated source files
 	SrcDeps          android.Paths
 	srcProviderFiles android.Paths
+
+	// Paths to specific build tools
+	Rustc         android.Path
+	Clang         android.Path
+	Llvm_ar       android.Path
+	Clippy_driver android.Path
+	Rustdoc       android.Path
 }
 
 type RustLibraries []RustLibrary
@@ -484,6 +497,8 @@
 	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.
@@ -513,7 +528,7 @@
 }
 
 type exportedFlagsProducer interface {
-	exportLinkDirs(...string)
+	exportLinkDirs(...android.Path)
 	exportLinkObjects(...android.Path)
 }
 
@@ -522,13 +537,13 @@
 }
 
 type flagExporter struct {
-	linkDirs    []string
+	linkDirs    android.Paths
 	linkObjects android.Paths
 	libDeps     android.Paths
 }
 
-func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
-	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
+func (flagExporter *flagExporter) exportLinkDirs(dirs ...android.Path) {
+	flagExporter.linkDirs = android.FirstUniquePaths(append(flagExporter.linkDirs, dirs...))
 }
 
 func (flagExporter *flagExporter) exportLinkObjects(flags ...android.Path) {
@@ -555,7 +570,7 @@
 
 type FlagExporterInfo struct {
 	Flags       []string
-	LinkDirs    []string // TODO: this should be android.Paths
+	LinkDirs    android.Paths
 	LinkObjects android.Paths
 	LibDeps     android.Paths
 }
@@ -925,6 +940,14 @@
 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,
@@ -1034,6 +1057,12 @@
 
 		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 {
@@ -1092,6 +1121,7 @@
 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}
@@ -1225,7 +1255,9 @@
 
 	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)
@@ -1238,6 +1270,17 @@
 			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)
@@ -1252,9 +1295,12 @@
 				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)
@@ -1263,10 +1309,18 @@
 				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)
@@ -1302,9 +1356,8 @@
 
 			if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
 				linkFile := rustDep.UnstrippedOutputFile()
-				linkDir := linkPathFromFilePath(linkFile)
 				if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
-					lib.exportLinkDirs(linkDir)
+					lib.exportLinkDirs(linkFile.Dir())
 				}
 			}
 
@@ -1331,7 +1384,7 @@
 				return
 			}
 
-			linkPath := linkPathFromFilePath(linkObject.Path())
+			linkPath := linkObject.Path().Dir()
 
 			exportDep := false
 			switch {
@@ -1385,7 +1438,7 @@
 					}
 					return
 				}
-				linkPath = linkPathFromFilePath(linkObject.Path())
+				linkPath = linkObject.Path().Dir()
 
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.AsPaths()...)
@@ -1420,6 +1473,25 @@
 			}
 		} else {
 			switch {
+			case depTag == buildToolDepTag:
+				buildTool := ctx.OtherModuleProvider(dep, android.PrebuiltBuildToolInfoProvider).(android.PrebuiltBuildToolInfo)
+				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Src)
+				depPaths.BuildToolDeps = append(depPaths.BuildToolDeps, buildTool.Deps...)
+				switch android.RemoveOptionalPrebuiltPrefix(dep.Name()) {
+				case "rustc":
+					depPaths.Rustc = buildTool.Src
+					// rustc expects the standard cc toolchain libraries (libdl, libm, libc, etc.)
+					// not to be under the __SBOX_SANDBOX_DIR__/ directory
+					depPaths.BuildToolSrcDeps = append(depPaths.BuildToolSrcDeps, buildTool.Deps...)
+				case "clang++":
+					depPaths.Clang = buildTool.Src
+				case "llvm-ar":
+					depPaths.Llvm_ar = buildTool.Src
+				case "clippy-driver":
+					depPaths.Clippy_driver = buildTool.Src
+				case "rustdoc":
+					depPaths.Rustdoc = buildTool.Src
+				}
 			case depTag == cc.CrtBeginDepTag:
 				depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, ""))
 			case depTag == cc.CrtEndDepTag:
@@ -1435,21 +1507,6 @@
 		}
 	})
 
-	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())
@@ -1473,20 +1530,22 @@
 		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.FirstUniqueStrings(depPaths.linkDirs)
+	depPaths.linkDirs = android.FirstUniquePaths(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
 }
 
@@ -1509,10 +1568,6 @@
 	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()
@@ -1555,6 +1610,15 @@
 			blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage})
 	}
 
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustc")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clippy-driver")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "rustdoc")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "clang++.real")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "lld")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "ld.lld")
+	ctx.AddFarVariationDependencies([]blueprint.Variation{}, buildToolDepTag, "llvm-ar")
+
 	// rlibs
 	rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: rlibVariation})
 	for _, lib := range deps.Rlibs {