Reapply "Clean environment variables to account for sandbox work directory."
with minor edits.

This reverts commit 9543d19b4b2c04e501e1e84f5d42e05af109535f.

Bug: 363037195
Change-Id: I4cb10b312b7f468185bfad12a16f9b4b64e7a58a
diff --git a/ui/build/config.go b/ui/build/config.go
index 6432348..711f325 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -41,6 +41,7 @@
 const (
 	envConfigDir = "vendor/google/tools/soong_config"
 	jsonSuffix   = "json"
+	abfsSrcDir   = "/src"
 )
 
 var (
@@ -214,6 +215,10 @@
 		sandboxConfig:         &SandboxConfig{},
 		ninjaWeightListSource: DEFAULT,
 	}
+	wd, err := os.Getwd()
+	if err != nil {
+		ctx.Fatalln("Failed to get working directory:", err)
+	}
 
 	// Skip soong tests by default on Linux
 	if runtime.GOOS == "linux" {
@@ -245,17 +250,13 @@
 
 	// Make sure OUT_DIR is set appropriately
 	if outDir, ok := ret.environ.Get("OUT_DIR"); ok {
-		ret.environ.Set("OUT_DIR", filepath.Clean(outDir))
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, filepath.Clean(outDir)))
 	} else {
 		outDir := "out"
 		if baseDir, ok := ret.environ.Get("OUT_DIR_COMMON_BASE"); ok {
-			if wd, err := os.Getwd(); err != nil {
-				ctx.Fatalln("Failed to get working directory:", err)
-			} else {
-				outDir = filepath.Join(baseDir, filepath.Base(wd))
-			}
+			outDir = filepath.Join(baseDir, filepath.Base(wd))
 		}
-		ret.environ.Set("OUT_DIR", outDir)
+		ret.environ.Set("OUT_DIR", ret.sandboxPath(wd, outDir))
 	}
 
 	// loadEnvConfig needs to know what the OUT_DIR is, so it should
@@ -350,6 +351,9 @@
 
 		// Use config.useN2 instead.
 		"SOONG_USE_N2",
+
+		// Leaks usernames into environment.
+		"HOME",
 	)
 
 	if ret.UseGoma() || ret.ForceUseGoma() {
@@ -361,12 +365,12 @@
 	ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1")
 
 	tmpDir := absPath(ctx, ret.TempDir())
-	ret.environ.Set("TMPDIR", tmpDir)
+	ret.environ.Set("TMPDIR", ret.sandboxPath(wd, tmpDir))
 
 	// Always set ASAN_SYMBOLIZER_PATH so that ASAN-based tools can symbolize any crashes
 	symbolizerPath := filepath.Join("prebuilts/clang/host", ret.HostPrebuiltTag(),
 		"llvm-binutils-stable/llvm-symbolizer")
-	ret.environ.Set("ASAN_SYMBOLIZER_PATH", absPath(ctx, symbolizerPath))
+	ret.environ.Set("ASAN_SYMBOLIZER_PATH", ret.sandboxPath(wd, absPath(ctx, symbolizerPath)))
 
 	// Precondition: the current directory is the top of the source tree
 	checkTopDir(ctx)
@@ -426,9 +430,9 @@
 	}
 
 	ret.environ.Unset("OVERRIDE_ANDROID_JAVA_HOME")
-	ret.environ.Set("JAVA_HOME", absJavaHome)
-	ret.environ.Set("ANDROID_JAVA_HOME", javaHome)
-	ret.environ.Set("ANDROID_JAVA8_HOME", java8Home)
+	ret.environ.Set("JAVA_HOME", ret.sandboxPath(wd, absJavaHome))
+	ret.environ.Set("ANDROID_JAVA_HOME", ret.sandboxPath(wd, javaHome))
+	ret.environ.Set("ANDROID_JAVA8_HOME", ret.sandboxPath(wd, java8Home))
 	ret.environ.Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
 
 	// b/286885495, https://bugzilla.redhat.com/show_bug.cgi?id=2227130: some versions of Fedora include patches
@@ -444,7 +448,7 @@
 		ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
 	}
 
-	ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
+	ret.environ.Set("BUILD_DATETIME_FILE", ret.sandboxPath(wd, buildDateTimeFile))
 
 	if _, ok := ret.environ.Get("BUILD_USERNAME"); !ok {
 		username := "unknown"
@@ -455,6 +459,7 @@
 		}
 		ret.environ.Set("BUILD_USERNAME", username)
 	}
+	ret.environ.Set("PWD", ret.sandboxPath(wd, wd))
 
 	if ret.UseRBE() {
 		for k, v := range getRBEVars(ctx, Config{ret}) {
@@ -1296,6 +1301,19 @@
 	return err == nil
 }
 
+func (c *configImpl) sandboxPath(base, in string) string {
+	if !c.UseABFS() {
+		return in
+	}
+
+	rel, err := filepath.Rel(base, in)
+	if err != nil {
+		return in
+	}
+
+	return filepath.Join(abfsSrcDir, rel)
+}
+
 func (c *configImpl) UseRBE() bool {
 	// These alternate modes of running Soong do not use RBE / reclient.
 	if c.Queryview() || c.JsonModuleGraph() {
@@ -1722,6 +1740,11 @@
 }
 
 func (c *configImpl) SkipMetricsUpload() bool {
+	// b/362625275 - Metrics upload sometimes prevents abfs unmount
+	if c.UseABFS() {
+		return true
+	}
+
 	return c.skipMetricsUpload
 }
 
diff --git a/ui/build/path.go b/ui/build/path.go
index 51ebff1..075bf2e 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -57,6 +57,22 @@
 	return ret
 }
 
+func updatePathForSandbox(config Config) {
+	wd, err := os.Getwd()
+	if err != nil {
+		return
+	}
+
+	var newPath []string
+	if path, ok := config.Environment().Get("PATH"); ok && path != "" {
+		entries := strings.Split(path, string(filepath.ListSeparator))
+		for _, ent := range entries {
+			newPath = append(newPath, config.sandboxPath(wd, ent))
+		}
+	}
+	config.Environment().Set("PATH", strings.Join(newPath, string(filepath.ListSeparator)))
+}
+
 // SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
 // places that does not need the full logging capabilities of path_interposer,
 // wants the minimal performance overhead, and still get the benefits of $PATH
@@ -121,6 +137,7 @@
 	// Set $PATH to be the directories containing the host tool symlinks, and
 	// the prebuilts directory for the current host OS.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
 
@@ -265,5 +282,6 @@
 	// Replace the $PATH variable with the path_interposer symlinks, and
 	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)
+	updatePathForSandbox(config)
 	config.pathReplaced = true
 }
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index d9ca854..95b71a7 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -50,7 +50,6 @@
 
 const (
 	nsjailPath = "prebuilts/build-tools/linux-x86/bin/nsjail"
-	abfsSrcDir = "/src"
 )
 
 var sandboxConfig struct {
@@ -148,20 +147,42 @@
 	return sandboxConfig.working
 }
 
-func (c *Cmd) srcDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.srcDir
+// Assumes input path is absolute, clean, and if applicable, an evaluated
+// symlink. If path is not a subdirectory of src dir or relative path
+// cannot be determined, return the input untouched.
+func (c *Cmd) relFromSrcDir(path string) string {
+	if !strings.HasPrefix(path, sandboxConfig.srcDir) {
+		return path
 	}
 
-	return sandboxConfig.srcDir + ":" + abfsSrcDir
+	rel, err := filepath.Rel(sandboxConfig.srcDir, path)
+	if err != nil {
+		return path
+	}
+
+	return rel
+}
+
+func (c *Cmd) dirArg(path string) string {
+	if !c.config.UseABFS() {
+		return path
+	}
+
+	rel := c.relFromSrcDir(path)
+
+	return path + ":" + filepath.Join(abfsSrcDir, rel)
+}
+
+func (c *Cmd) srcDirArg() string {
+	return c.dirArg(sandboxConfig.srcDir)
 }
 
 func (c *Cmd) outDirArg() string {
-	if !c.config.UseABFS() {
-		return sandboxConfig.outDir
-	}
+	return c.dirArg(sandboxConfig.outDir)
+}
 
-	return sandboxConfig.outDir + ":" + filepath.Join(abfsSrcDir, sandboxConfig.outDir)
+func (c *Cmd) distDirArg() string {
+	return c.dirArg(sandboxConfig.distDir)
 }
 
 // When configured to use ABFS, we need to allow the creation of the /src
@@ -187,8 +208,17 @@
 	return args
 }
 
+func (c *Cmd) workDir() string {
+	if !c.config.UseABFS() {
+		wd, _ := os.Getwd()
+		return wd
+	}
+
+	return abfsSrcDir
+}
+
 func (c *Cmd) wrapSandbox() {
-	wd, _ := os.Getwd()
+	wd := c.workDir()
 
 	var sandboxArgs []string
 	sandboxArgs = append(sandboxArgs,
@@ -226,7 +256,7 @@
 	)
 
 	sandboxArgs = append(sandboxArgs,
-		c.readMountArgs()...
+		c.readMountArgs()...,
 	)
 
 	sandboxArgs = append(sandboxArgs,
@@ -264,7 +294,7 @@
 
 	if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
 		//Mount dist dir as read-write if it already exists
-		sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+		sandboxArgs = append(sandboxArgs, "-B", c.distDirArg())
 	}
 
 	if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {