Enable goma in soong

When the UseGoma flag is set, put all rules except the C compilation
rule in an externally defined local_pool, which will have been created
by kati.  The gomacc wrapper will already be in the CC_WRAPPER
environment variable.

Bug: 31142427
Change-Id: I699d4edff2e302eee398dad8692ceb14721a628c
diff --git a/android/config.go b/android/config.go
index 21a7233..b7aac02 100644
--- a/android/config.go
+++ b/android/config.go
@@ -369,6 +369,10 @@
 	return false
 }
 
+func (c *config) UseGoma() bool {
+	return Bool(c.ProductVariables.UseGoma)
+}
+
 func (c *config) LibartImgHostBaseAddress() string {
 	return "0x60000000"
 }
diff --git a/android/defs.go b/android/defs.go
index 9c6527d..6e28de7 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -28,7 +28,7 @@
 	// A phony rule that is not the built-in Ninja phony rule.  The built-in
 	// phony rule has special behavior that is sometimes not desired.  See the
 	// Ninja docs for more details.
-	Phony = pctx.StaticRule("Phony",
+	Phony = pctx.AndroidStaticRule("Phony",
 		blueprint.RuleParams{
 			Command:     "# phony $out",
 			Description: "phony $out",
@@ -37,7 +37,7 @@
 	// GeneratedFile is a rule for indicating that a given file was generated
 	// while running soong.  This allows the file to be cleaned up if it ever
 	// stops being generated by soong.
-	GeneratedFile = pctx.StaticRule("GeneratedFile",
+	GeneratedFile = pctx.AndroidStaticRule("GeneratedFile",
 		blueprint.RuleParams{
 			Command:     "# generated $out",
 			Description: "generated $out",
@@ -45,7 +45,7 @@
 		})
 
 	// A copy rule.
-	Cp = pctx.StaticRule("Cp",
+	Cp = pctx.AndroidStaticRule("Cp",
 		blueprint.RuleParams{
 			Command:     "cp $cpPreserveSymlinks $cpFlags $in $out",
 			Description: "cp $out",
@@ -53,26 +53,29 @@
 		"cpFlags")
 
 	// A timestamp touch rule.
-	Touch = pctx.StaticRule("Touch",
+	Touch = pctx.AndroidStaticRule("Touch",
 		blueprint.RuleParams{
 			Command:     "touch $out",
 			Description: "touch $out",
 		})
 
 	// A symlink rule.
-	Symlink = pctx.StaticRule("Symlink",
+	Symlink = pctx.AndroidStaticRule("Symlink",
 		blueprint.RuleParams{
 			Command:     "ln -f -s $fromPath $out",
 			Description: "symlink $out",
 		},
 		"fromPath")
 
-	ErrorRule = pctx.StaticRule("Error",
+	ErrorRule = pctx.AndroidStaticRule("Error",
 		blueprint.RuleParams{
 			Command:     `echo "$error" && false`,
 			Description: "error building $out",
 		},
 		"error")
+
+	// Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value
+	localPool = blueprint.NewBuiltinPool("local_pool")
 )
 
 func init() {
diff --git a/android/glob.go b/android/glob.go
index 34b3de4..0457cbc 100644
--- a/android/glob.go
+++ b/android/glob.go
@@ -43,7 +43,7 @@
 
 	// globRule rule traverses directories to produce a list of files that match $glob
 	// and writes it to $out if it has changed, and writes the directories to $out.d
-	globRule = pctx.StaticRule("globRule",
+	globRule = pctx.AndroidStaticRule("globRule",
 		blueprint.RuleParams{
 			Command:     fmt.Sprintf(`%s -o $out $excludes "$glob"`, globCmd),
 			CommandDeps: []string{globCmd},
diff --git a/android/package_ctx.go b/android/package_ctx.go
index 56ba2d8..ee826c8 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -131,3 +131,35 @@
 		return JoinWithPrefix(paths.Strings(), prefix), nil
 	})
 }
+
+type RuleParams struct {
+	blueprint.RuleParams
+	GomaSupported bool
+}
+
+// AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
+func (p AndroidPackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
+	argNames ...string) blueprint.Rule {
+	return p.AndroidRuleFunc(name, func(interface{}) (blueprint.RuleParams, error) {
+		return params, nil
+	}, argNames...)
+}
+
+// AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
+func (p AndroidPackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
+	argNames ...string) blueprint.Rule {
+	return p.StaticRule(name, params, argNames...)
+}
+
+func (p AndroidPackageContext) AndroidRuleFunc(name string,
+	f func(interface{}) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
+	return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
+		params, err := f(config)
+		if config.(Config).UseGoma() && params.Pool == nil {
+			// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
+			// local parallelism value
+			params.Pool = localPool
+		}
+		return params, err
+	}, argNames...)
+}
diff --git a/android/variable.go b/android/variable.go
index be2407d..b99e485 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -101,6 +101,7 @@
 	Cpusets                    *bool `json:",omitempty"`
 	Schedboost                 *bool `json:",omitempty"`
 	Binder32bit                *bool `json:",omitempty"`
+	UseGoma                    *bool `json:",omitempty"`
 
 	DevicePrefer32BitExecutables *bool `json:",omitempty"`
 	HostPrefer32BitExecutables   *bool `json:",omitempty"`