Merge "Add quotes to sourcepath"
diff --git a/Android.bp b/Android.bp
index ac50166..ccab727 100644
--- a/Android.bp
+++ b/Android.bp
@@ -192,6 +192,9 @@
     srcs: [
         "genrule/genrule.go",
     ],
+    testSrcs: [
+        "genrule/genrule_test.go",
+    ],
     pluginFor: ["soong_build"],
 }
 
diff --git a/android/arch.go b/android/arch.go
index 57899cd..95f8803 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -295,46 +295,47 @@
 		return
 	}
 
-	if !module.base().ArchSpecific() {
+	base := module.base()
+
+	if !base.ArchSpecific() {
 		return
 	}
 
-	osClasses := module.base().OsClassSupported()
+	osClasses := base.OsClassSupported()
 
 	var moduleTargets []Target
 	primaryModules := make(map[int]bool)
 
 	for _, class := range osClasses {
-		targets := mctx.Config().Targets[class]
-		if len(targets) == 0 {
+		classTargets := mctx.Config().Targets[class]
+		if len(classTargets) == 0 {
 			continue
 		}
-		var multilib string
-		switch class {
-		case Device:
-			multilib = String(module.base().commonProperties.Target.Android.Compile_multilib)
-		case Host, HostCross:
-			multilib = String(module.base().commonProperties.Target.Host.Compile_multilib)
-		}
-		if multilib == "" {
-			multilib = String(module.base().commonProperties.Compile_multilib)
-		}
-		if multilib == "" {
-			multilib = module.base().commonProperties.Default_multilib
-		}
-		var prefer32 bool
-		switch class {
-		case Device:
-			prefer32 = mctx.Config().DevicePrefer32BitExecutables()
-		case HostCross:
-			// Windows builds always prefer 32-bit
-			prefer32 = true
-		}
 		// only the primary arch in the recovery partition
 		if module.InstallInRecovery() {
-			targets = []Target{mctx.Config().Targets[Device][0]}
+			classTargets = []Target{mctx.Config().Targets[Device][0]}
 		}
-		targets, err := decodeMultilib(multilib, targets, prefer32)
+
+		var multilib string
+		switch class {
+		case Device:
+			multilib = String(base.commonProperties.Target.Android.Compile_multilib)
+		case Host, HostCross:
+			multilib = String(base.commonProperties.Target.Host.Compile_multilib)
+		}
+		if multilib == "" {
+			multilib = String(base.commonProperties.Compile_multilib)
+		}
+		if multilib == "" {
+			multilib = base.commonProperties.Default_multilib
+		}
+
+		prefer32 := false
+		if base.prefer32 != nil {
+			prefer32 = base.prefer32(mctx, base, class)
+		}
+
+		targets, err := decodeMultilib(multilib, classTargets, prefer32)
 		if err != nil {
 			mctx.ModuleErrorf("%s", err.Error())
 		}
@@ -345,7 +346,7 @@
 	}
 
 	if len(moduleTargets) == 0 {
-		module.base().commonProperties.Enabled = boolPtr(false)
+		base.commonProperties.Enabled = boolPtr(false)
 		return
 	}
 
diff --git a/android/config.go b/android/config.go
index db5d004..4b10552 100644
--- a/android/config.go
+++ b/android/config.go
@@ -241,6 +241,8 @@
 		},
 	}
 
+	config.BuildOsVariant = config.Targets[Host][0].String()
+
 	return testConfig
 }
 
diff --git a/android/module.go b/android/module.go
index 92b11ed..01766b4 100644
--- a/android/module.go
+++ b/android/module.go
@@ -442,6 +442,8 @@
 
 	// For tests
 	buildParams []BuildParams
+
+	prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
 }
 
 func (a *ModuleBase) AddProperties(props ...interface{}) {
@@ -456,6 +458,10 @@
 	return a.buildParams
 }
 
+func (a *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool) {
+	a.prefer32 = prefer32
+}
+
 // Name returns the name of the module.  It may be overridden by individual module types, for
 // example prebuilts will prepend prebuilt_ to the name.
 func (a *ModuleBase) Name() string {
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 046512f..fbc9de2 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -49,6 +49,7 @@
 	properties prebuiltEtcProperties
 
 	sourceFilePath         Path
+	outputFilePath         OutputPath
 	installDirPath         OutputPath
 	additionalDependencies *Paths
 }
@@ -84,9 +85,25 @@
 	p.additionalDependencies = &paths
 }
 
+func (p *PrebuiltEtc) OutputFile() OutputPath {
+	return p.outputFilePath
+}
+
+func (p *PrebuiltEtc) SubDir() string {
+	return String(p.properties.Sub_dir)
+}
+
 func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
 	p.sourceFilePath = ctx.ExpandSource(String(p.properties.Src), "src")
+	p.outputFilePath = PathForModuleOut(ctx, ctx.ModuleName()).OutputPath
 	p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
+
+	// This ensures that outputFilePath has the same name as this module.
+	ctx.Build(pctx, BuildParams{
+		Rule:   Cp,
+		Output: p.outputFilePath,
+		Input:  p.sourceFilePath,
+	})
 }
 
 func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
@@ -101,7 +118,7 @@
 			fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
 			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
 			fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
-			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.sourceFilePath.String())
+			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.outputFilePath.String())
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
 			fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name)
 			if p.additionalDependencies != nil {
diff --git a/cc/cc.go b/cc/cc.go
index d31a38a..d04485d 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -406,6 +406,17 @@
 		c.AddProperties(feature.props()...)
 	}
 
+	c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
+		switch class {
+		case android.Device:
+			return ctx.Config().DevicePrefer32BitExecutables()
+		case android.HostCross:
+			// Windows builds always prefer 32-bit
+			return true
+		default:
+			return false
+		}
+	})
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
 
 	android.InitDefaultableModule(c)
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 2e49c16..dd52a0e 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -36,7 +36,6 @@
 			"performance*",
 			"-google-readability*",
 			"-google-runtime-references",
-			"-performance-noexcept-move-constructor",
 		}, ",")
 	})
 
diff --git a/genrule/genrule.go b/genrule/genrule.go
index e3823c5..f19e2aa 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -102,8 +102,9 @@
 
 	taskGenerator taskFunc
 
-	deps android.Paths
-	rule blueprint.Rule
+	deps       android.Paths
+	rule       blueprint.Rule
+	rawCommand string
 
 	exportedIncludeDirs android.Paths
 
@@ -287,6 +288,7 @@
 	genDir := android.PathForModuleGen(ctx)
 	// Escape the command for the shell
 	rawCommand = "'" + strings.Replace(rawCommand, "'", `'\''`, -1) + "'"
+	g.rawCommand = rawCommand
 	sandboxCommand := fmt.Sprintf("$sboxCmd --sandbox-path %s --output-root %s -c %s %s $allouts",
 		sandboxPath, genDir, rawCommand, depfilePlaceholder)
 
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
new file mode 100644
index 0000000..0d690d4
--- /dev/null
+++ b/genrule/genrule_test.go
@@ -0,0 +1,374 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package genrule
+
+import (
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"android/soong/android"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_java_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testContext(config android.Config, bp string,
+	fs map[string][]byte) *android.TestContext {
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
+	ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(GenRuleFactory))
+	ctx.RegisterModuleType("tool", android.ModuleFactoryAdaptor(toolFactory))
+	ctx.Register()
+
+	bp += `
+		tool {
+			name: "tool",
+		}
+
+		filegroup {
+			name: "tool_files",
+			srcs: [
+				"tool_file1",
+				"tool_file2",
+			],
+		}
+
+		filegroup {
+			name: "1tool_file",
+			srcs: [
+				"tool_file1",
+			],
+		}
+
+		filegroup {
+			name: "ins",
+			srcs: [
+				"in1",
+				"in2",
+			],
+		}
+
+		filegroup {
+			name: "1in",
+			srcs: [
+				"in1",
+			],
+		}
+
+		filegroup {
+			name: "empty",
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+		"tool":       nil,
+		"tool_file1": nil,
+		"tool_file2": nil,
+		"in1":        nil,
+		"in2":        nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
+
+func TestGenruleCmd(t *testing.T) {
+	testcases := []struct {
+		name string
+		prop string
+
+		err    string
+		expect string
+	}{
+		{
+			name: "empty location tool",
+			prop: `
+				tools: ["tool"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			expect: "out/tool > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "empty location tool file",
+			prop: `
+				tool_files: ["tool_file1"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			expect: "tool_file1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "empty location tool file fg",
+			prop: `
+				tool_files: [":1tool_file"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			expect: "tool_file1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "empty location tool and tool file",
+			prop: `
+				tools: ["tool"],
+				tool_files: ["tool_file1"],
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			expect: "out/tool > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "tool",
+			prop: `
+				tools: ["tool"],
+				out: ["out"],
+				cmd: "$(location tool) > $(out)",
+			`,
+			expect: "out/tool > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "tool file",
+			prop: `
+				tool_files: ["tool_file1"],
+				out: ["out"],
+				cmd: "$(location tool_file1) > $(out)",
+			`,
+			expect: "tool_file1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "tool file fg",
+			prop: `
+				tool_files: [":1tool_file"],
+				out: ["out"],
+				cmd: "$(location tool_file1) > $(out)",
+			`,
+			expect: "tool_file1 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "tool files",
+			prop: `
+				tool_files: [":tool_files"],
+				out: ["out"],
+				cmd: "$(location tool_file1) $(location tool_file2) > $(out)",
+			`,
+			expect: "tool_file1 tool_file2 > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "in1",
+			prop: `
+				srcs: ["in1"],
+				out: ["out"],
+				cmd: "cat $(in) > $(out)",
+			`,
+			expect: "cat ${in} > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "in1 fg",
+			prop: `
+				srcs: [":1in"],
+				out: ["out"],
+				cmd: "cat $(in) > $(out)",
+			`,
+			expect: "cat ${in} > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "ins",
+			prop: `
+				srcs: ["in1", "in2"],
+				out: ["out"],
+				cmd: "cat $(in) > $(out)",
+			`,
+			expect: "cat ${in} > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "ins fg",
+			prop: `
+				srcs: [":ins"],
+				out: ["out"],
+				cmd: "cat $(in) > $(out)",
+			`,
+			expect: "cat ${in} > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "outs",
+			prop: `
+				out: ["out", "out2"],
+				cmd: "echo foo > $(out)",
+			`,
+			expect: "echo foo > __SBOX_OUT_FILES__",
+		},
+		{
+			name: "depfile",
+			prop: `
+				out: ["out"],
+				depfile: true,
+				cmd: "echo foo > $(out) && touch $(depfile)",
+			`,
+			expect: "echo foo > __SBOX_OUT_FILES__ && touch __SBOX_DEPFILE__",
+		},
+		{
+			name: "gendir",
+			prop: `
+				out: ["out"],
+				cmd: "echo foo > $(genDir)/foo && cp $(genDir)/foo $(out)",
+			`,
+			expect: "echo foo > __SBOX_OUT_DIR__/foo && cp __SBOX_OUT_DIR__/foo __SBOX_OUT_FILES__",
+		},
+
+		{
+			name: "error empty location",
+			prop: `
+				out: ["out"],
+				cmd: "$(location) > $(out)",
+			`,
+			err: "at least one `tools` or `tool_files` is required if $(location) is used",
+		},
+		{
+			name: "error location",
+			prop: `
+				out: ["out"],
+				cmd: "echo foo > $(location missing)",
+			`,
+			err: `unknown location label "missing"`,
+		},
+		{
+			name: "error variable",
+			prop: `
+					out: ["out"],
+					srcs: ["in1"],
+					cmd: "echo $(foo) > $(out)",
+			`,
+			err: `unknown variable '$(foo)'`,
+		},
+		{
+			name: "error depfile",
+			prop: `
+				out: ["out"],
+				cmd: "echo foo > $(out) && touch $(depfile)",
+			`,
+			err: "$(depfile) used without depfile property",
+		},
+		{
+			name: "error no depfile",
+			prop: `
+				out: ["out"],
+				depfile: true,
+				cmd: "echo foo > $(out)",
+			`,
+			err: "specified depfile=true but did not include a reference to '${depfile}' in cmd",
+		},
+		{
+			name: "error no out",
+			prop: `
+				cmd: "echo foo > $(out)",
+			`,
+			err: "must have at least one output file",
+		},
+	}
+
+	for _, test := range testcases {
+		t.Run(test.name, func(t *testing.T) {
+			config := android.TestArchConfig(buildDir, nil)
+			bp := "genrule {\n"
+			bp += "name: \"gen\",\n"
+			bp += test.prop
+			bp += "}\n"
+
+			ctx := testContext(config, bp, nil)
+
+			_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+			if errs == nil {
+				_, errs = ctx.PrepareBuildActions(config)
+			}
+			if errs == nil && test.err != "" {
+				t.Fatalf("want error %q, got no error", test.err)
+			} else if errs != nil && test.err == "" {
+				android.FailIfErrored(t, errs)
+			} else if test.err != "" {
+				if len(errs) != 1 {
+					t.Errorf("want 1 error, got %d errors:", len(errs))
+					for _, err := range errs {
+						t.Errorf("   %s", err.Error())
+					}
+					t.FailNow()
+				}
+				if !strings.Contains(errs[0].Error(), test.err) {
+					t.Fatalf("want %q, got %q", test.err, errs[0].Error())
+				}
+				return
+			}
+
+			gen := ctx.ModuleForTests("gen", "").Module().(*Module)
+			if gen.rawCommand != "'"+test.expect+"'" {
+				t.Errorf("want %q, got %q", test.expect, gen.rawCommand)
+			}
+		})
+	}
+
+}
+
+type testTool struct {
+	android.ModuleBase
+	outputFile android.Path
+}
+
+func toolFactory() android.Module {
+	module := &testTool{}
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	return module
+}
+
+func (t *testTool) DepsMutator(ctx android.BottomUpMutatorContext) {}
+
+func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	t.outputFile = android.PathForTesting("out", ctx.ModuleName())
+}
+
+func (t *testTool) HostToolPath() android.OptionalPath {
+	return android.OptionalPathForPath(t.outputFile)
+}
+
+var _ HostToolProvider = (*testTool)(nil)
diff --git a/java/aar.go b/java/aar.go
index 29f5597..35fb96f 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -359,7 +359,7 @@
 
 	module.androidLibraryProperties.BuildAAR = true
 
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	InitJavaModule(module, android.DeviceSupported)
 	return module
 }
 
@@ -382,6 +382,7 @@
 
 type AARImport struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 	prebuilt android.Prebuilt
 
 	properties AARImportProperties
@@ -555,6 +556,6 @@
 	module.AddProperties(&module.properties)
 
 	android.InitPrebuiltModule(module, &module.properties.Aars)
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	InitJavaModule(module, android.DeviceSupported)
 	return module
 }
diff --git a/java/app.go b/java/app.go
index f8bef1c..dc5296d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -208,6 +208,10 @@
 		&module.aaptProperties,
 		&module.appProperties)
 
+	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
+		return class == android.Device && ctx.Config().DevicePrefer32BitApps()
+	})
+
 	InitJavaModule(module, android.DeviceSupported)
 	return module
 }
diff --git a/java/java.go b/java/java.go
index 8b354d9..b4b8feb 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1493,7 +1493,6 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
-	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -1508,7 +1507,6 @@
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
 	InitJavaModule(module, android.HostSupported)
-	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -1624,6 +1622,7 @@
 
 type Import struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
 	prebuilt android.Prebuilt
 
 	properties ImportProperties
@@ -1752,7 +1751,7 @@
 	module.AddProperties(&module.properties)
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
-	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }
 
@@ -1762,7 +1761,7 @@
 	module.AddProperties(&module.properties)
 
 	android.InitPrebuiltModule(module, &module.properties.Jars)
-	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+	InitJavaModule(module, android.HostSupported)
 	return module
 }
 
@@ -1792,6 +1791,13 @@
 		&CompilerProperties{},
 		&CompilerDeviceProperties{},
 		&android.ProtoProperties{},
+		&aaptProperties{},
+		&androidLibraryProperties{},
+		&appProperties{},
+		&appTestProperties{},
+		&ImportProperties{},
+		&AARImportProperties{},
+		&sdkLibraryProperties{},
 	)
 
 	android.InitDefaultsModule(module)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 3e6908b..a8c3b11 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -691,7 +691,6 @@
 	module := &sdkLibrary{}
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.deviceProperties)
-	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
-	android.InitDefaultableModule(module)
+	InitJavaModule(module, android.DeviceSupported)
 	return module
 }
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 7886466..8c51641 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -39,6 +39,12 @@
 	Error:   true,
 }
 
+var Log = PathConfig{
+	Symlink: true,
+	Log: true,
+	Error: false,
+}
+
 // The configuration used if the tool is not listed in the config below.
 // Currently this will create the symlink, but log and error when it's used. In
 // the future, I expect the symlink to be removed, and this will be equivalent
@@ -104,7 +110,7 @@
 	"openssl":   Allowed,
 	"paste":     Allowed,
 	"patch":     Allowed,
-	"perl":      Allowed,
+	"perl":      Log,
 	"pgrep":     Allowed,
 	"pkill":     Allowed,
 	"ps":        Allowed,
@@ -128,7 +134,6 @@
 	"sleep":     Allowed,
 	"sort":      Allowed,
 	"stat":      Allowed,
-	"sum":       Allowed,
 	"tar":       Allowed,
 	"tail":      Allowed,
 	"tee":       Allowed,