Use WriteFileRule instead of custom echo commands

These instances could use WriteFileRule instead of
making their own shell code to write a file.

Test: Presubmits
Change-Id: I9c809b2164a68b4ce1c22fbbd0d7497240110b39
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index e9c97d0..fc63c3b 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -36,11 +36,6 @@
 )
 
 var (
-	writeBazelFile = pctx.AndroidStaticRule("bazelWriteFileRule", blueprint.RuleParams{
-		Command:        `sed "s/\\\\n/\n/g" ${out}.rsp >${out}`,
-		Rspfile:        "${out}.rsp",
-		RspfileContent: "${content}",
-	}, "content")
 	_                 = pctx.HostBinToolVariable("bazelBuildRunfilesTool", "build-runfiles")
 	buildRunfilesRule = pctx.AndroidStaticRule("bazelBuildRunfiles", blueprint.RuleParams{
 		Command:     "${bazelBuildRunfilesTool} ${in} ${outDir}",
@@ -1089,19 +1084,8 @@
 		// because this would cause circular dependency. So, until we move aquery processing
 		// to the 'android' package, we need to handle special cases here.
 		if buildStatement.Mnemonic == "FileWrite" || buildStatement.Mnemonic == "SourceSymlinkManifest" {
-			// Pass file contents as the value of the rule's "content" argument.
-			// Escape newlines and $ in the contents (the action "writeBazelFile" restores "\\n"
-			// back to the newline, and Ninja reads $$ as $.
-			escaped := strings.ReplaceAll(strings.ReplaceAll(buildStatement.FileContents, "\n", "\\n"),
-				"$", "$$")
-			ctx.Build(pctx, BuildParams{
-				Rule:        writeBazelFile,
-				Output:      PathForBazelOut(ctx, buildStatement.OutputPaths[0]),
-				Description: fmt.Sprintf("%s %s", buildStatement.Mnemonic, buildStatement.OutputPaths[0]),
-				Args: map[string]string{
-					"content": escaped,
-				},
-			})
+			out := PathForBazelOut(ctx, buildStatement.OutputPaths[0])
+			WriteFileRuleVerbatim(ctx, out, buildStatement.FileContents)
 		} else if buildStatement.Mnemonic == "SymlinkTree" {
 			// build-runfiles arguments are the manifest file and the target directory
 			// where it creates the symlink tree according to this manifest (and then
diff --git a/android/buildinfo_prop.go b/android/buildinfo_prop.go
index acebdbb..46f6488 100644
--- a/android/buildinfo_prop.go
+++ b/android/buildinfo_prop.go
@@ -61,11 +61,10 @@
 		return
 	}
 
-	rule := NewRuleBuilder(pctx, ctx)
-	cmd := rule.Command().Text("(")
+	lines := make([]string, 0)
 
 	writeString := func(str string) {
-		cmd.Text(`echo "` + str + `" && `)
+		lines = append(lines, str)
 	}
 
 	writeString("# begin build properties")
@@ -142,8 +141,7 @@
 
 	writeString("# end build properties")
 
-	cmd.Text("true) > ").Output(p.outputFilePath)
-	rule.Build("build.prop", "generating build.prop")
+	WriteFileRule(ctx, p.outputFilePath, strings.Join(lines, "\n"))
 
 	if !p.installable() {
 		p.SkipInstall()
diff --git a/android/defs.go b/android/defs.go
index 9ae360e..6e5bb05 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -174,10 +174,15 @@
 // WriteFileRule creates a ninja rule to write contents to a file.  The contents will be escaped
 // so that the file contains exactly the contents passed to the function, plus a trailing newline.
 func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) {
+	WriteFileRuleVerbatim(ctx, outputFile, content+"\n")
+}
+
+// WriteFileRuleVerbatim creates a ninja rule to write contents to a file.  The contents will be
+// escaped so that the file contains exactly the contents passed to the function.
+func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) {
 	// This is MAX_ARG_STRLEN subtracted with some safety to account for shell escapes
 	const SHARD_SIZE = 131072 - 10000
 
-	content += "\n"
 	if len(content) > SHARD_SIZE {
 		var chunks WritablePaths
 		for i, c := range ShardString(content, SHARD_SIZE) {