Add support for privileged apps to androidmk

Fixes: 221894523
Test: Added unit tests
Test: Manual test
Change-Id: I2285e4e24d94d519ee68dde74edc2d4fb2120146
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 295b0e5..954f8d0 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"sort"
+	"strconv"
 	"strings"
 
 	mkparser "android/soong/androidmk/parser"
@@ -623,6 +624,16 @@
 	return err
 }
 
+// Assigns a given boolean value to a given variable in the result bp file. See
+// setVariable documentation for more information about prefix and name.
+func makeBlueprintBoolAssignment(ctx variableAssignmentContext, prefix, name string, value bool) error {
+	expressionValue, err := stringToBoolValue(strconv.FormatBool(value))
+	if err == nil {
+		err = setVariable(ctx.file, false, prefix, name, expressionValue, true)
+	}
+	return err
+}
+
 // If variable is a literal variable name, return the name, otherwise return ""
 func varLiteralName(variable mkparser.Variable) string {
 	if len(variable.Name.Variables) == 0 {
@@ -647,7 +658,11 @@
 	varname := ""
 	fixed := ""
 	val := ctx.mkvalue
+
 	if len(val.Variables) == 1 && varLiteralName(val.Variables[0]) != "" && len(val.Strings) == 2 && val.Strings[0] == "" {
+		if varLiteralName(val.Variables[0]) == "PRODUCT_OUT" && val.Strings[1] == "/system/priv-app" {
+			return makeBlueprintBoolAssignment(ctx, "", "privileged", true)
+		}
 		fixed = val.Strings[1]
 		varname = val.Variables[0].Name.Strings[0]
 		// TARGET_OUT_OPTIONAL_EXECUTABLES puts the artifact in xbin, which is
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index b8316a3..aaafdc7 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -411,6 +411,24 @@
 	return exp, nil
 }
 
+// If local is set to true, then the variable will be added as a part of the
+// variable at file.bpPos. For example, if file.bpPos references a module,
+// then calling this method will set a property on that module if local is set
+// to true. Otherwise, the Variable will be created at the root of the file.
+//
+// prefix should be populated with the top level value to be assigned, and
+// name with a sub-value. If prefix is empty, then name is the top level value.
+// For example, if prefix is "foo" and name is "bar" with a value of "baz", then
+// the following variable will be generated:
+//
+// foo {
+//   bar: "baz"
+// }
+//
+// If prefix is the empty string and name is "foo" with a value of "bar", the
+// following variable will be generated (if it is a property):
+//
+// foo: "bar"
 func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
 	if prefix != "" {
 		name = prefix + "." + name
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index e8b6f78..2176361 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1675,6 +1675,21 @@
 }
 `,
 	},
+	{
+		desc: "privileged app",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
+include $(BUILD_PACKAGE)
+		`,
+		expected: `
+android_app {
+	name: "foo",
+	privileged: true
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/androidmk/parser/make_strings.go b/androidmk/parser/make_strings.go
index aac4c4e..8030326 100644
--- a/androidmk/parser/make_strings.go
+++ b/androidmk/parser/make_strings.go
@@ -24,14 +24,24 @@
 // A MakeString is a string that may contain variable substitutions in it.
 // It can be considered as an alternating list of raw Strings and variable
 // substitutions, where the first and last entries in the list must be raw
-// Strings (possibly empty).  A MakeString that starts with a variable
-// will have an empty first raw string, and a MakeString that ends with a
-// variable will have an empty last raw string.  Two sequential Variables
-// will have an empty raw string between them.
+// Strings (possibly empty). The entirety of the text before the first variable,
+// between two variables, and after the last variable will be considered a
+// single String value. A MakeString that starts with a variable will have an
+// empty first raw string, and a MakeString that ends with a  variable will have
+// an empty last raw string.  Two sequential Variables will have an empty raw
+// string between them.
 //
 // The MakeString is stored as two lists, a list of raw Strings and a list
 // of Variables.  The raw string list is always one longer than the variable
 // list.
+//
+// For example, "$(FOO)/bar/baz" will be represented as the
+// following lists:
+//
+// {
+//   Strings: ["", "/bar/baz"],
+//   Variables: ["FOO"]
+// }
 type MakeString struct {
 	StringPos Pos
 	Strings   []string