Merge "soong_ui path.go: improve comments."
diff --git a/ui/build/path.go b/ui/build/path.go
index 6f5cf78..86e61c0 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -29,6 +29,9 @@
 	"android/soong/ui/metrics"
 )
 
+// parsePathDir returns the list of filenames of readable files in a directory.
+// This does not recurse into subdirectories, and does not contain subdirectory
+// names in the list.
 func parsePathDir(dir string) []string {
 	f, err := os.Open(dir)
 	if err != nil {
@@ -54,10 +57,12 @@
 	return ret
 }
 
-// A "lite" version of SetupPath used for dumpvars, or other places that need
-// minimal overhead (but at the expense of logging). If tmpDir is empty, the
-// default TMPDIR is used from config.
+// 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
+// hermeticity.
 func SetupLitePath(ctx Context, config Config, tmpDir string) {
+	// Don't replace the path twice.
 	if config.pathReplaced {
 		return
 	}
@@ -67,6 +72,7 @@
 
 	origPath, _ := config.Environment().Get("PATH")
 
+	// If tmpDir is empty, the default TMPDIR is used from config.
 	if tmpDir == "" {
 		tmpDir, _ = config.Environment().Get("TMPDIR")
 	}
@@ -74,8 +80,10 @@
 	ensureEmptyDirectoriesExist(ctx, myPath)
 
 	os.Setenv("PATH", origPath)
+	// Iterate over the ACL configuration of host tools for this build.
 	for name, pathConfig := range paths.Configuration {
 		if !pathConfig.Symlink {
+			// Excludes 'Forbidden' and 'LinuxOnlyPrebuilt' PathConfigs.
 			continue
 		}
 
@@ -88,6 +96,7 @@
 			continue
 		}
 
+		// Symlink allowed host tools into a directory for hermeticity.
 		err = os.Symlink(origExec, filepath.Join(myPath, name))
 		if err != nil {
 			ctx.Fatalln("Failed to create symlink:", err)
@@ -96,14 +105,26 @@
 
 	myPath, _ = filepath.Abs(myPath)
 
+	// Set up the checked-in prebuilts path directory for the current host OS.
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	// 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)
 	config.pathReplaced = true
 }
 
+// SetupPath uses the path_interposer to intercept calls to $PATH binaries, and
+// communicates with the interposer to validate allowed $PATH binaries at
+// runtime, using logs as a medium.
+//
+// This results in hermetic directories in $PATH containing only allowed host
+// tools for the build, and replaces $PATH to contain *only* these directories,
+// and enables an incremental restriction of tools allowed in the $PATH without
+// breaking existing use cases.
 func SetupPath(ctx Context, config Config) {
+	// Don't replace $PATH twice.
 	if config.pathReplaced {
 		return
 	}
@@ -112,9 +133,11 @@
 	defer ctx.EndTrace()
 
 	origPath, _ := config.Environment().Get("PATH")
+	// The directory containing symlinks from binaries in $PATH to the interposer.
 	myPath := filepath.Join(config.OutDir(), ".path")
 	interposer := myPath + "_interposer"
 
+	// Bootstrap the path_interposer Go binary with microfactory.
 	var cfg microfactory.Config
 	cfg.Map("android/soong", "build/soong")
 	cfg.TrimPath, _ = filepath.Abs(".")
@@ -122,15 +145,20 @@
 		ctx.Fatalln("Failed to build path interposer:", err)
 	}
 
+	// Save the original $PATH in a file.
 	if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
 		ctx.Fatalln("Failed to write original path:", err)
 	}
 
+	// Communication with the path interposer works over log entries. Set up the
+	// listener channel for the log entries here.
 	entries, err := paths.LogListener(ctx.Context, interposer+"_log")
 	if err != nil {
 		ctx.Fatalln("Failed to listen for path logs:", err)
 	}
 
+	// Loop over all log entry listener channels to validate usage of only
+	// allowed PATH tools at runtime.
 	go func() {
 		for log := range entries {
 			curPid := os.Getpid()
@@ -140,6 +168,8 @@
 					break
 				}
 			}
+			// Compute the error message along with the process tree, including
+			// parents, for this log line.
 			procPrints := []string{
 				"See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
 			}
@@ -150,6 +180,7 @@
 				}
 			}
 
+			// Validate usage against disallowed or missing PATH tools.
 			config := paths.GetConfig(log.Basename)
 			if config.Error {
 				ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
@@ -165,8 +196,10 @@
 		}
 	}()
 
+	// Create the .path directory.
 	ensureEmptyDirectoriesExist(ctx, myPath)
 
+	// Compute the full list of binaries available in the original $PATH.
 	var execs []string
 	for _, pathEntry := range filepath.SplitList(origPath) {
 		if pathEntry == "" {
@@ -185,8 +218,14 @@
 		ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.")
 	}
 
+	// Create symlinks from the path_interposer binary to all binaries for each
+	// directory in the original $PATH. This ensures that during the build,
+	// every call to a binary that's expected to be in the $PATH will be
+	// intercepted by the path_interposer binary, and validated with the
+	// LogEntry listener above at build time.
 	for _, name := range execs {
 		if !paths.GetConfig(name).Symlink {
+			// Ignore host tools that shouldn't be symlinked.
 			continue
 		}
 
@@ -200,11 +239,13 @@
 
 	myPath, _ = filepath.Abs(myPath)
 
-	// We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of
-	// them.
+	// We put some prebuilts in $PATH, since it's infeasible to add dependencies
+	// for all of them.
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	// Replace the $PATH variable with the path_interposer symlinks, and
+	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)
 	config.pathReplaced = true
 }