Use aquery to declare bazel actions in the ninja file.

This effectively moves execution of Bazel actions outside of soong_build
and alongside ninja execution of the actual ninja files, whether that be
by ninja or by Bazel itself.

This almost allows for mixed builds and Bazel-as-Ninja-executor to
coexist, but requires hacks explained in b/175307058.

Test: Treehugger
Test: lunch aosp_flame && USE_BAZEL_ANALYSIS=1 m libc
Test: lunch aosp_flame && USE_BAZEL=1 USE_BAZEL_ANALYSIS=1 m libc,
though this requires a hack of the main BUILD file. See b/175307058

Change-Id: Ia2f6b0f1057e8cea3809de66d8287f13d84b510c
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index d810726..81ca475 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -26,9 +26,10 @@
 	"strings"
 	"sync"
 
+	"github.com/google/blueprint/bootstrap"
+
 	"android/soong/bazel"
 	"android/soong/shared"
-	"github.com/google/blueprint/bootstrap"
 )
 
 type CqueryRequestType int
@@ -60,6 +61,12 @@
 
 	// Returns true if bazel is enabled for the given configuration.
 	BazelEnabled() bool
+
+	// Returns the bazel output base (the root directory for all bazel intermediate outputs).
+	OutputBase() string
+
+	// Returns build statements which should get registered to reflect Bazel's outputs.
+	BuildStatementsToRegister() []bazel.BuildStatement
 }
 
 // A context object which tracks queued requests that need to be made to Bazel,
@@ -76,6 +83,9 @@
 	requestMutex sync.Mutex         // requests can be written in parallel
 
 	results map[cqueryKey]string // Results of cquery requests after Bazel invocations
+
+	// Build statements which should get registered to reflect Bazel's outputs.
+	buildStatements []bazel.BuildStatement
 }
 
 var _ BazelContext = &bazelContext{}
@@ -103,6 +113,14 @@
 	return true
 }
 
+func (m MockBazelContext) OutputBase() string {
+	return "outputbase"
+}
+
+func (m MockBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return []bazel.BuildStatement{}
+}
+
 var _ BazelContext = MockBazelContext{}
 
 func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
@@ -123,10 +141,18 @@
 	panic("unimplemented")
 }
 
+func (m noopBazelContext) OutputBase() string {
+	return ""
+}
+
 func (n noopBazelContext) BazelEnabled() bool {
 	return false
 }
 
+func (m noopBazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return []bazel.BuildStatement{}
+}
+
 func NewBazelContext(c *config) (BazelContext, error) {
 	// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
 	// are production ready.
@@ -241,14 +267,32 @@
 
 func (context *bazelContext) mainBzlFileContents() []byte {
 	contents := `
+#####################################################
 # This file is generated by soong_build. Do not edit.
+#####################################################
+
 def _mixed_build_root_impl(ctx):
     return [DefaultInfo(files = depset(ctx.files.deps))]
 
+# Rule representing the root of the build, to depend on all Bazel targets that
+# are required for the build. Building this target will build the entire Bazel
+# build tree.
 mixed_build_root = rule(
     implementation = _mixed_build_root_impl,
     attrs = {"deps" : attr.label_list()},
 )
+
+def _phony_root_impl(ctx):
+    return []
+
+# Rule to depend on other targets but build nothing.
+# This is useful as follows: building a target of this rule will generate
+# symlink forests for all dependencies of the target, without executing any
+# actions of the build.
+phony_root = rule(
+    implementation = _phony_root_impl,
+    attrs = {"deps" : attr.label_list()},
+)
 `
 	return []byte(contents)
 }
@@ -268,11 +312,15 @@
 func (context *bazelContext) mainBuildFileContents() []byte {
 	formatString := `
 # This file is generated by soong_build. Do not edit.
-load(":main.bzl", "mixed_build_root")
+load(":main.bzl", "mixed_build_root", "phony_root")
 
 mixed_build_root(name = "buildroot",
     deps = [%s],
 )
+
+phony_root(name = "phonyroot",
+    deps = [":buildroot"],
+)
 `
 	var buildRootDeps []string = nil
 	for val, _ := range context.requests {
@@ -379,22 +427,46 @@
 		}
 	}
 
-	// Issue a build command.
-	// TODO(cparsons): Invoking bazel execution during soong_build should be avoided;
-	// bazel actions should either be added to the Ninja file and executed later,
-	// or bazel should handle execution.
+	// Issue an aquery command to retrieve action information about the bazel build tree.
+	//
 	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
-	_, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", []string{buildroot_label})
+	var aqueryOutput string
+	aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery",
+		[]string{fmt.Sprintf("deps(%s)", buildroot_label),
+			// Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's
+			// proto sources, which would add a number of unnecessary dependencies.
+			"--output=jsonproto"})
 
 	if err != nil {
 		return err
 	}
 
+	context.buildStatements = bazel.AqueryBuildStatements([]byte(aqueryOutput))
+
+	// Issue a build command of the phony root to generate symlink forests for dependencies of the
+	// Bazel build. This is necessary because aquery invocations do not generate this symlink forest,
+	// but some of symlinks may be required to resolve source dependencies of the build.
+	_, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build",
+		[]string{"//:phonyroot"})
+
+	if err != nil {
+		return err
+	}
+
+	fmt.Printf("Build statements %s", context.buildStatements)
 	// Clear requests.
 	context.requests = map[cqueryKey]bool{}
 	return nil
 }
 
+func (context *bazelContext) BuildStatementsToRegister() []bazel.BuildStatement {
+	return context.buildStatements
+}
+
+func (context *bazelContext) OutputBase() string {
+	return context.outputBase
+}
+
 // Singleton used for registering BUILD file ninja dependencies (needed
 // for correctness of builds which use Bazel.
 func BazelSingleton() Singleton {
@@ -404,18 +476,45 @@
 type bazelSingleton struct{}
 
 func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) {
-	if ctx.Config().BazelContext.BazelEnabled() {
-		bazelBuildList := absolutePath(filepath.Join(
-			filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
-		ctx.AddNinjaFileDeps(bazelBuildList)
+	// bazelSingleton is a no-op if mixed-soong-bazel-builds are disabled.
+	if !ctx.Config().BazelContext.BazelEnabled() {
+		return
+	}
 
-		data, err := ioutil.ReadFile(bazelBuildList)
-		if err != nil {
-			ctx.Errorf(err.Error())
+	// Add ninja file dependencies for files which all bazel invocations require.
+	bazelBuildList := absolutePath(filepath.Join(
+		filepath.Dir(bootstrap.ModuleListFile), "bazel.list"))
+	ctx.AddNinjaFileDeps(bazelBuildList)
+
+	data, err := ioutil.ReadFile(bazelBuildList)
+	if err != nil {
+		ctx.Errorf(err.Error())
+	}
+	files := strings.Split(strings.TrimSpace(string(data)), "\n")
+	for _, file := range files {
+		ctx.AddNinjaFileDeps(file)
+	}
+
+	// Register bazel-owned build statements (obtained from the aquery invocation).
+	for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
+		rule := NewRuleBuilder(pctx, ctx)
+		cmd := rule.Command()
+		cmd.Text(fmt.Sprintf("cd %s/execroot/__main__ && %s",
+			ctx.Config().BazelContext.OutputBase(), buildStatement.Command))
+
+		for _, outputPath := range buildStatement.OutputPaths {
+			cmd.ImplicitOutput(PathForBazelOut(ctx, outputPath))
 		}
-		files := strings.Split(strings.TrimSpace(string(data)), "\n")
-		for _, file := range files {
-			ctx.AddNinjaFileDeps(file)
+		for _, inputPath := range buildStatement.InputPaths {
+			cmd.Implicit(PathForBazelOut(ctx, inputPath))
 		}
+
+		// This is required to silence warnings pertaining to unexpected timestamps. Particularly,
+		// some Bazel builtins (such as files in the bazel_tools directory) have far-future
+		// timestamps. Without restat, Ninja would emit warnings that the input files of a
+		// build statement have later timestamps than the outputs.
+		rule.Restat()
+
+		rule.Build(fmt.Sprintf("bazel %s", index), buildStatement.Mnemonic)
 	}
 }