Ignore bazel-generated paths in dangling rule test

Bazel is expected to generate some files and symlinks that will not be
created by aquery, we explicitly ignore files that are in bazel output
paths but are not in a generated file directory.

Test: $ m --bazel-mode-staging checkbuild and verify it gets past
   dangling rule test
Fixes: 258396112
Change-Id: I6dc45ea2613c9e1488ad3eda2313033c717217ff
diff --git a/ui/build/config.go b/ui/build/config.go
index de10112..896a854 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -896,6 +896,10 @@
 	return filepath.Join(c.OutDir(), "bazel")
 }
 
+func (c *configImpl) bazelOutputBase() string {
+	return filepath.Join(c.BazelOutDir(), "output")
+}
+
 func (c *configImpl) SoongOutDir() string {
 	return filepath.Join(c.OutDir(), "soong")
 }
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 4aded17..ee2b7c8 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -418,7 +418,7 @@
 	// Bazel's HOME var is set to an output subdirectory which doesn't exist. This
 	// prevents Bazel from file I/O in the actual user HOME directory.
 	soongBuildEnv.Set("BAZEL_HOME", absPath(ctx, filepath.Join(config.BazelOutDir(), "bazelhome")))
-	soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
+	soongBuildEnv.Set("BAZEL_OUTPUT_BASE", config.bazelOutputBase())
 	soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
 	soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
 	soongBuildEnv.Set("LOG_DIR", config.LogsDir())
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 86c8568..2efc732 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -18,14 +18,44 @@
 	"bufio"
 	"fmt"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"sort"
 	"strings"
+	"sync"
 
 	"android/soong/ui/metrics"
 	"android/soong/ui/status"
 )
 
+var (
+	// bazel output paths are in __main__/bazel-out/<config-specific-path>/bin
+	bazelOutputPathRegexOnce sync.Once
+	bazelOutputPathRegexp    *regexp.Regexp
+)
+
+func bazelOutputPathPattern(config Config) *regexp.Regexp {
+	bazelOutputPathRegexOnce.Do(func() {
+		// Bazel output files are in <Bazel output base>/execroot/__main__/bazel-out/<config>/bin
+		bazelOutRoot := filepath.Join(regexp.QuoteMeta(config.bazelOutputBase()), "execroot", "__main__", "bazel-out")
+		bazelOutputPathRegexp = regexp.MustCompile(bazelOutRoot + "/[^/]+/bin")
+	})
+	return bazelOutputPathRegexp
+}
+
+func ignoreBazelPath(config Config, path string) bool {
+	bazelRoot := filepath.Join(config.bazelOutputBase(), "execroot")
+	// Don't check bazel output regexp unless it is Bazel path
+	if strings.HasPrefix(path, bazelRoot) {
+		bazelOutputRegexp := bazelOutputPathPattern(config)
+		// if the file is a bazel path that is _not_ a Bazel generated file output, we rely on Bazel to
+		// ensure the paths to exist. If it _is_ a Bazel output path, we expect that it should be built
+		// by Ninja.
+		return !bazelOutputRegexp.MatchString(path)
+	}
+	return false
+}
+
 // Checks for files in the out directory that have a rule that depends on them but no rule to
 // create them. This catches a common set of build failures where a rule to generate a file is
 // deleted (either by deleting a module in an Android.mk file, or by modifying the build system
@@ -97,6 +127,10 @@
 			// full build rules in the primary build.ninja file.
 			continue
 		}
+
+		if ignoreBazelPath(config, line) {
+			continue
+		}
 		danglingRules[line] = true
 	}