Merge "Executables in APEXes have root:shell"
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index db88685..d16ac93 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -739,27 +739,31 @@
 		true: "product_variables.pdk"},
 }
 
-func mydir(args []string) string {
-	return "."
+func mydir(args []string) []string {
+	return []string{"."}
 }
 
-func allFilesUnder(wildcard string) func(args []string) string {
-	return func(args []string) string {
-		dir := ""
+func allFilesUnder(wildcard string) func(args []string) []string {
+	return func(args []string) []string {
+		dirs := []string{""}
 		if len(args) > 0 {
-			dir = strings.TrimSpace(args[0])
+			dirs = strings.Fields(args[0])
 		}
 
-		return fmt.Sprintf("%s/**/"+wildcard, dir)
+		paths := make([]string, len(dirs))
+		for i := range paths {
+			paths[i] = fmt.Sprintf("%s/**/"+wildcard, dirs[i])
+		}
+		return paths
 	}
 }
 
-func allSubdirJavaFiles(args []string) string {
-	return "**/*.java"
+func allSubdirJavaFiles(args []string) []string {
+	return []string{"**/*.java"}
 }
 
-func includeIgnored(args []string) string {
-	return include_ignored
+func includeIgnored(args []string) []string {
+	return []string{include_ignored}
 }
 
 var moduleTypes = map[string]string{
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 0f6c5ac..40fc9f3 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -554,6 +554,10 @@
 			LOCAL_SRC_FILES := d.java
 			LOCAL_UNINSTALLABLE_MODULE := false
 			include $(BUILD_JAVA_LIBRARY)
+
+			include $(CLEAR_VARS)
+			LOCAL_SRC_FILES := $(call all-java-files-under, src gen)
+			include $(BUILD_STATIC_JAVA_LIBRARY)
 		`,
 		expected: `
 			java_library {
@@ -574,6 +578,13 @@
 				installable: true,
 				srcs: ["d.java"],
 			}
+
+			java_library {
+				srcs: [
+					"src/**/*.java",
+					"gen/**/*.java",
+				],
+			}
 		`,
 	},
 	{
diff --git a/androidmk/cmd/androidmk/values.go b/androidmk/cmd/androidmk/values.go
index d240a01..90f2e74 100644
--- a/androidmk/cmd/androidmk/values.go
+++ b/androidmk/cmd/androidmk/values.go
@@ -29,6 +29,14 @@
 	}
 }
 
+func stringListToStringValueList(list []string) []bpparser.Expression {
+	valList := make([]bpparser.Expression, len(list))
+	for i, l := range list {
+		valList[i] = stringToStringValue(l)
+	}
+	return valList
+}
+
 func addValues(val1, val2 bpparser.Expression) (bpparser.Expression, error) {
 	if val1 == nil {
 		return val2, nil
@@ -63,7 +71,10 @@
 
 	for i, s := range ms.Strings[1:] {
 		if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
-			val, err = addValues(val, stringToStringValue(ret))
+			if len(ret) > 1 {
+				return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
+			}
+			val, err = addValues(val, stringToStringValue(ret[0]))
 		} else {
 			name := ms.Variables[i].Name
 			if !name.Const() {
@@ -125,9 +136,7 @@
 	for _, f := range fields {
 		if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
 			if ret, ok := f.Variables[0].EvalFunction(scope); ok {
-				listValue.Values = append(listValue.Values, &bpparser.String{
-					Value: ret,
-				})
+				listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
 			} else {
 				// Variable by itself, variable is probably a list
 				if !f.Variables[0].Name.Const() {
diff --git a/androidmk/parser/scope.go b/androidmk/parser/scope.go
index 167e470..8111c89 100644
--- a/androidmk/parser/scope.go
+++ b/androidmk/parser/scope.go
@@ -21,13 +21,13 @@
 type Scope interface {
 	Get(name string) string
 	Set(name, value string)
-	Call(name string, args []string) string
-	SetFunc(name string, f func([]string) string)
+	Call(name string, args []string) []string
+	SetFunc(name string, f func([]string) []string)
 }
 
 type scope struct {
 	variables map[string]string
-	functions map[string]func([]string) string
+	functions map[string]func([]string) []string
 	parent    Scope
 }
 
@@ -47,22 +47,22 @@
 	s.variables[name] = value
 }
 
-func (s *scope) Call(name string, args []string) string {
+func (s *scope) Call(name string, args []string) []string {
 	if f, ok := s.functions[name]; ok {
 		return f(args)
 	}
 
-	return "<func:'" + name + "' unset>"
+	return []string{"<func:'" + name + "' unset>"}
 }
 
-func (s *scope) SetFunc(name string, f func([]string) string) {
+func (s *scope) SetFunc(name string, f func([]string) []string) {
 	s.functions[name] = f
 }
 
 func NewScope(parent Scope) Scope {
 	return &scope{
 		variables: make(map[string]string),
-		functions: make(map[string]func([]string) string),
+		functions: make(map[string]func([]string) []string),
 		parent:    parent,
 	}
 }
@@ -74,7 +74,7 @@
 	builtinScope[builtinDollar] = "$"
 }
 
-func (v Variable) EvalFunction(scope Scope) (string, bool) {
+func (v Variable) EvalFunction(scope Scope) ([]string, bool) {
 	f := v.Name.SplitN(" \t", 2)
 	if len(f) > 1 && f[0].Const() {
 		fname := f[0].Value(nil)
@@ -88,17 +88,20 @@
 			if fname == "call" {
 				return scope.Call(argVals[0], argVals[1:]), true
 			} else {
-				return "__builtin_func:" + fname + " " + strings.Join(argVals, " "), true
+				return []string{"__builtin_func:" + fname + " " + strings.Join(argVals, " ")}, true
 			}
 		}
 	}
 
-	return "", false
+	return []string{""}, false
 }
 
 func (v Variable) Value(scope Scope) string {
 	if ret, ok := v.EvalFunction(scope); ok {
-		return ret
+		if len(ret) > 1 {
+			panic("Expected a single value, but instead got a list")
+		}
+		return ret[0]
 	}
 	if scope == nil {
 		panic("Cannot take the value of a variable in a nil scope")
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index e2e4368..1bcbec1 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -78,7 +78,6 @@
 	"bash":      Allowed,
 	"bc":        Allowed,
 	"bzip2":     Allowed,
-	"chmod":     Allowed,
 	"cp":        Allowed,
 	"date":      Allowed,
 	"dd":        Allowed,
@@ -154,6 +153,7 @@
 	// On linux we'll use the toybox version of these instead
 	"basename": Toybox,
 	"cat":      Toybox,
+	"chmod":    Toybox,
 	"cmp":      Toybox,
 	"comm":     Toybox,
 	"cut":      Toybox,