Merge "Build contexts files with Soong"
diff --git a/android/androidmk.go b/android/androidmk.go
index 42e1439..2a3748e 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -32,6 +32,8 @@
 	RegisterSingletonType("androidmk", AndroidMkSingleton)
 }
 
+// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to
+// use the Custom function.
 type AndroidMkDataProvider interface {
 	AndroidMk() AndroidMkData
 	BaseModuleName() string
@@ -57,6 +59,200 @@
 
 type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
 
+// Allows modules to customize their Android*.mk output.
+type AndroidMkEntriesProvider interface {
+	AndroidMkEntries() AndroidMkEntries
+	BaseModuleName() string
+}
+
+type AndroidMkEntries struct {
+	Class           string
+	SubName         string
+	DistFile        OptionalPath
+	OutputFile      OptionalPath
+	Disabled        bool
+	Include         string
+	Required        []string
+	Host_required   []string
+	Target_required []string
+
+	header bytes.Buffer
+	footer bytes.Buffer
+
+	AddCustomEntries func(name, prefix, moduleDir string, entries *AndroidMkEntries)
+
+	EntryMap   map[string][]string
+	entryOrder []string
+}
+
+func (a *AndroidMkEntries) SetString(name, value string) {
+	if _, ok := a.EntryMap[name]; !ok {
+		a.entryOrder = append(a.entryOrder, name)
+	}
+	a.EntryMap[name] = []string{value}
+}
+
+func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) {
+	if flag {
+		if _, ok := a.EntryMap[name]; !ok {
+			a.entryOrder = append(a.entryOrder, name)
+		}
+		a.EntryMap[name] = []string{"true"}
+	}
+}
+
+func (a *AndroidMkEntries) AddStrings(name string, value ...string) {
+	if len(value) == 0 {
+		return
+	}
+	if _, ok := a.EntryMap[name]; !ok {
+		a.entryOrder = append(a.entryOrder, name)
+	}
+	a.EntryMap[name] = append(a.EntryMap[name], value...)
+}
+
+func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
+	a.EntryMap = make(map[string][]string)
+	amod := mod.(Module).base()
+	name := amod.BaseModuleName()
+
+	if a.Include == "" {
+		a.Include = "$(BUILD_PREBUILT)"
+	}
+	a.Required = append(a.Required, amod.commonProperties.Required...)
+	a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
+	a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
+
+	// Fill in the header part.
+	if len(amod.commonProperties.Dist.Targets) > 0 {
+		distFile := a.DistFile
+		if !distFile.Valid() {
+			distFile = a.OutputFile
+		}
+		if distFile.Valid() {
+			dest := filepath.Base(distFile.String())
+
+			if amod.commonProperties.Dist.Dest != nil {
+				var err error
+				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			if amod.commonProperties.Dist.Suffix != nil {
+				ext := filepath.Ext(dest)
+				suffix := *amod.commonProperties.Dist.Suffix
+				dest = strings.TrimSuffix(dest, ext) + suffix + ext
+			}
+
+			if amod.commonProperties.Dist.Dir != nil {
+				var err error
+				if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
+					// This was checked in ModuleBase.GenerateBuildActions
+					panic(err)
+				}
+			}
+
+			goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
+			fmt.Fprintln(&a.header, ".PHONY:", goals)
+			fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
+				goals, distFile.String(), dest)
+		}
+	}
+
+	fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
+
+	// Collect make variable assignment entries.
+	a.SetString("LOCAL_PATH", filepath.Dir(bpPath))
+	a.SetString("LOCAL_MODULE", name+a.SubName)
+	a.SetString("LOCAL_MODULE_CLASS", a.Class)
+	a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String())
+	a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...)
+	a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...)
+	a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...)
+
+	archStr := amod.Arch().ArchType.String()
+	host := false
+	switch amod.Os().Class {
+	case Host:
+		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
+		if archStr != "common" {
+			a.SetString("LOCAL_MODULE_HOST_ARCH", archStr)
+		}
+		host = true
+	case HostCross:
+		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
+		if archStr != "common" {
+			a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr)
+		}
+		host = true
+	case Device:
+		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
+		if archStr != "common" {
+			a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr)
+		}
+
+		a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...)
+		a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...)
+		a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary))
+		if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
+			a.SetString("LOCAL_VENDOR_MODULE", "true")
+		}
+		a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific))
+		a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific))
+		a.SetBoolIfTrue("LOCAL_PRODUCT_SERVICES_MODULE", Bool(amod.commonProperties.Product_services_specific))
+		if amod.commonProperties.Owner != nil {
+			a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner)
+		}
+	}
+
+	if amod.noticeFile.Valid() {
+		a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+	}
+
+	if host {
+		makeOs := amod.Os().String()
+		if amod.Os() == Linux || amod.Os() == LinuxBionic {
+			makeOs = "linux"
+		}
+		a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
+		a.SetString("LOCAL_IS_HOST_MODULE", "true")
+	}
+
+	prefix := ""
+	if amod.ArchSpecific() {
+		switch amod.Os().Class {
+		case Host:
+			prefix = "HOST_"
+		case HostCross:
+			prefix = "HOST_CROSS_"
+		case Device:
+			prefix = "TARGET_"
+
+		}
+
+		if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType {
+			prefix = "2ND_" + prefix
+		}
+	}
+	blueprintDir := filepath.Dir(bpPath)
+	if a.AddCustomEntries != nil {
+		a.AddCustomEntries(name, prefix, blueprintDir, a)
+	}
+
+	// Write to footer.
+	fmt.Fprintln(&a.footer, "include "+a.Include)
+}
+
+func (a *AndroidMkEntries) write(w io.Writer) {
+	w.Write(a.header.Bytes())
+	for _, name := range a.entryOrder {
+		fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " "))
+	}
+	w.Write(a.footer.Bytes())
+}
+
 func AndroidMkSingleton() Singleton {
 	return &androidMkSingleton{}
 }
@@ -159,6 +355,8 @@
 		return translateAndroidModule(ctx, w, mod, x)
 	case bootstrap.GoBinaryTool:
 		return translateGoBinaryModule(ctx, w, mod, x)
+	case AndroidMkEntriesProvider:
+		return translateAndroidMkEntriesModule(ctx, w, mod, x)
 	default:
 		return nil
 	}
@@ -178,37 +376,32 @@
 func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
 	provider AndroidMkDataProvider) error {
 
-	name := provider.BaseModuleName()
 	amod := mod.(Module).base()
-
-	if !amod.Enabled() {
-		return nil
-	}
-
-	if amod.commonProperties.SkipInstall {
-		return nil
-	}
-
-	if !amod.commonProperties.NamespaceExportedToMake {
-		// TODO(jeffrygaston) do we want to validate that there are no modules being
-		// exported to Kati that depend on this module?
+	if shouldSkipAndroidMkProcessing(amod) {
 		return nil
 	}
 
 	data := provider.AndroidMk()
-
 	if data.Include == "" {
 		data.Include = "$(BUILD_PREBUILT)"
 	}
 
-	data.Required = append(data.Required, amod.commonProperties.Required...)
-	data.Host_required = append(data.Host_required, amod.commonProperties.Host_required...)
-	data.Target_required = append(data.Target_required, amod.commonProperties.Target_required...)
-
-	// Make does not understand LinuxBionic
-	if amod.Os() == LinuxBionic {
-		return nil
+	// Get the preamble content through AndroidMkEntries logic.
+	entries := AndroidMkEntries{
+		Class:           data.Class,
+		SubName:         data.SubName,
+		DistFile:        data.DistFile,
+		OutputFile:      data.OutputFile,
+		Disabled:        data.Disabled,
+		Include:         data.Include,
+		Required:        data.Required,
+		Host_required:   data.Host_required,
+		Target_required: data.Target_required,
 	}
+	entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
+	// preamble doesn't need the footer content.
+	entries.footer = bytes.Buffer{}
+	entries.write(&data.preamble)
 
 	prefix := ""
 	if amod.ArchSpecific() {
@@ -227,112 +420,7 @@
 		}
 	}
 
-	if len(amod.commonProperties.Dist.Targets) > 0 {
-		distFile := data.DistFile
-		if !distFile.Valid() {
-			distFile = data.OutputFile
-		}
-		if distFile.Valid() {
-			dest := filepath.Base(distFile.String())
-
-			if amod.commonProperties.Dist.Dest != nil {
-				var err error
-				dest, err = validateSafePath(*amod.commonProperties.Dist.Dest)
-				if err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			if amod.commonProperties.Dist.Suffix != nil {
-				ext := filepath.Ext(dest)
-				suffix := *amod.commonProperties.Dist.Suffix
-				dest = strings.TrimSuffix(dest, ext) + suffix + ext
-			}
-
-			if amod.commonProperties.Dist.Dir != nil {
-				var err error
-				dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest)
-				if err != nil {
-					// This was checked in ModuleBase.GenerateBuildActions
-					panic(err)
-				}
-			}
-
-			goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
-			fmt.Fprintln(&data.preamble, ".PHONY:", goals)
-			fmt.Fprintf(&data.preamble, "$(call dist-for-goals,%s,%s:%s)\n",
-				goals, distFile.String(), dest)
-		}
-	}
-
-	fmt.Fprintln(&data.preamble, "\ninclude $(CLEAR_VARS)")
-	fmt.Fprintln(&data.preamble, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod)))
-	fmt.Fprintln(&data.preamble, "LOCAL_MODULE :=", name+data.SubName)
-	fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class)
-	fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String())
-	WriteRequiredModulesSettings(&data.preamble, data)
-
-	archStr := amod.Arch().ArchType.String()
-	host := false
-	switch amod.Os().Class {
-	case Host:
-		// Make cannot identify LOCAL_MODULE_HOST_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_ARCH :=", archStr)
-		}
-		host = true
-	case HostCross:
-		// Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
-		}
-		host = true
-	case Device:
-		// Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common.
-		if archStr != "common" {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
-		}
-
-		if len(amod.commonProperties.Init_rc) > 0 {
-			fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " "))
-		}
-		if len(amod.commonProperties.Vintf_fragments) > 0 {
-			fmt.Fprintln(&data.preamble, "LOCAL_VINTF_FRAGMENTS := ", strings.Join(amod.commonProperties.Vintf_fragments, " "))
-		}
-		if Bool(amod.commonProperties.Proprietary) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Device_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Product_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_MODULE := true")
-		}
-		if Bool(amod.commonProperties.Product_services_specific) {
-			fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_SERVICES_MODULE := true")
-		}
-		if amod.commonProperties.Owner != nil {
-			fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner)
-		}
-	}
-
-	if amod.noticeFile.Valid() {
-		fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", amod.noticeFile.String())
-	}
-
-	if host {
-		makeOs := amod.Os().String()
-		if amod.Os() == Linux || amod.Os() == LinuxBionic {
-			makeOs = "linux"
-		}
-		fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_OS :=", makeOs)
-		fmt.Fprintln(&data.preamble, "LOCAL_IS_HOST_MODULE := true")
-	}
-
+	name := provider.BaseModuleName()
 	blueprintDir := filepath.Dir(ctx.BlueprintFile(mod))
 
 	if data.Custom != nil {
@@ -362,14 +450,29 @@
 	fmt.Fprintln(w, "include "+data.Include)
 }
 
-func WriteRequiredModulesSettings(w io.Writer, data AndroidMkData) {
-	if len(data.Required) > 0 {
-		fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
+	provider AndroidMkEntriesProvider) error {
+	if shouldSkipAndroidMkProcessing(mod.(Module).base()) {
+		return nil
 	}
-	if len(data.Host_required) > 0 {
-		fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+
+	entries := provider.AndroidMkEntries()
+	entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod)
+
+	entries.write(w)
+
+	return nil
+}
+
+func shouldSkipAndroidMkProcessing(module *ModuleBase) bool {
+	if !module.commonProperties.NamespaceExportedToMake {
+		// TODO(jeffrygaston) do we want to validate that there are no modules being
+		// exported to Kati that depend on this module?
+		return true
 	}
-	if len(data.Target_required) > 0 {
-		fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
-	}
+
+	return !module.Enabled() ||
+		module.commonProperties.SkipInstall ||
+		// Make does not understand LinuxBionic
+		module.Os() == LinuxBionic
 }
diff --git a/android/config.go b/android/config.go
index 18ce6c3..3495ad2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -198,6 +198,14 @@
 
 // TestConfig returns a Config object suitable for using for tests
 func TestConfig(buildDir string, env map[string]string) Config {
+	envCopy := make(map[string]string)
+	for k, v := range env {
+		envCopy[k] = v
+	}
+
+	// Copy the real PATH value to the test environment, it's needed by HostSystemTool() used in x86_darwin_host.go
+	envCopy["PATH"] = originalEnv["PATH"]
+
 	config := &config{
 		productVariables: productVariables{
 			DeviceName:                  stringPtr("test_device"),
@@ -212,7 +220,7 @@
 
 		buildDir:     buildDir,
 		captureBuild: true,
-		env:          env,
+		env:          envCopy,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 3cadaeb..bec24c7 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -14,10 +14,7 @@
 
 package android
 
-import (
-	"fmt"
-	"io"
-)
+import "strconv"
 
 // TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
 
@@ -134,37 +131,25 @@
 	})
 }
 
-func (p *PrebuiltEtc) AndroidMk() AndroidMkData {
-	return AndroidMkData{
-		Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
-			nameSuffix := ""
-			if p.inRecovery() && !p.onlyInRecovery() {
-				nameSuffix = ".recovery"
-			}
-			fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
-			fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
-			fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
-			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
-			if p.commonProperties.Owner != nil {
-				fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *p.commonProperties.Owner)
-			}
-			fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
-			if p.Host() {
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
-			}
-			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 :=", p.outputFilePath.Base())
-			fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !p.Installable())
-			WriteRequiredModulesSettings(w, data)
+func (p *PrebuiltEtc) AndroidMkEntries() AndroidMkEntries {
+	nameSuffix := ""
+	if p.inRecovery() && !p.onlyInRecovery() {
+		nameSuffix = ".recovery"
+	}
+	return AndroidMkEntries{
+		Class:      "ETC",
+		SubName:    nameSuffix,
+		OutputFile: OptionalPathForPath(p.outputFilePath),
+		AddCustomEntries: func(name, prefix, moduleDir string, entries *AndroidMkEntries) {
+			entries.SetString("LOCAL_MODULE_TAGS", "optional")
+			entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+			entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+			entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
 			if p.additionalDependencies != nil {
-				fmt.Fprint(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=")
 				for _, path := range *p.additionalDependencies {
-					fmt.Fprint(w, " "+path.String())
+					entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
 				}
-				fmt.Fprintln(w, "")
 			}
-			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 		},
 	}
 }
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index fbdbc97..08700ae 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -15,12 +15,10 @@
 package android
 
 import (
-	"bufio"
-	"bytes"
 	"io/ioutil"
 	"os"
 	"path/filepath"
-	"strings"
+	"reflect"
 	"testing"
 )
 
@@ -139,49 +137,37 @@
 }
 
 func TestPrebuiltEtcAndroidMk(t *testing.T) {
-	ctx, _ := testPrebuiltEtc(t, `
+	ctx, config := testPrebuiltEtc(t, `
 		prebuilt_etc {
 			name: "foo",
 			src: "foo.conf",
 			owner: "abc",
 			filename_from_src: true,
+			required: ["modA", "moduleB"],
+			host_required: ["hostModA", "hostModB"],
+			target_required: ["targetModA"],
 		}
 	`)
 
-	data := AndroidMkData{}
-	data.Required = append(data.Required, "modA", "moduleB")
-	data.Host_required = append(data.Host_required, "hostModA", "hostModB")
-	data.Target_required = append(data.Target_required, "targetModA")
-
-	expected := map[string]string{
-		"LOCAL_MODULE":                  "foo",
-		"LOCAL_MODULE_CLASS":            "ETC",
-		"LOCAL_MODULE_OWNER":            "abc",
-		"LOCAL_INSTALLED_MODULE_STEM":   "foo.conf",
-		"LOCAL_REQUIRED_MODULES":        "modA moduleB",
-		"LOCAL_HOST_REQUIRED_MODULES":   "hostModA hostModB",
-		"LOCAL_TARGET_REQUIRED_MODULES": "targetModA",
+	expected := map[string][]string{
+		"LOCAL_MODULE":                  {"foo"},
+		"LOCAL_MODULE_CLASS":            {"ETC"},
+		"LOCAL_MODULE_OWNER":            {"abc"},
+		"LOCAL_INSTALLED_MODULE_STEM":   {"foo.conf"},
+		"LOCAL_REQUIRED_MODULES":        {"modA", "moduleB"},
+		"LOCAL_HOST_REQUIRED_MODULES":   {"hostModA", "hostModB"},
+		"LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"},
 	}
 
 	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
-	buf := &bytes.Buffer{}
-	mod.AndroidMk().Custom(buf, "foo", "", "", data)
-	for k, expected := range expected {
-		found := false
-		scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
-		for scanner.Scan() {
-			line := scanner.Text()
-			tok := strings.Split(line, " := ")
-			if tok[0] == k {
-				found = true
-				if tok[1] != expected {
-					t.Errorf("Incorrect %s '%s', expected '%s'", k, tok[1], expected)
-				}
+	entries := AndroidMkEntriesForTest(t, config, "", mod)
+	for k, expectedValue := range expected {
+		if value, ok := entries.EntryMap[k]; ok {
+			if !reflect.DeepEqual(value, expectedValue) {
+				t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue)
 			}
-		}
-
-		if !found {
-			t.Errorf("No %s defined, saw %s", k, buf.String())
+		} else {
+			t.Errorf("No %s defined, saw %q", k, entries.EntryMap)
 		}
 	}
 }
diff --git a/android/testing.go b/android/testing.go
index aee6855..c0db75e 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -371,3 +371,14 @@
 		}
 	}
 }
+
+func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) AndroidMkEntries {
+	var p AndroidMkEntriesProvider
+	var ok bool
+	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
+		t.Errorf("module does not implmement AndroidMkEntriesProvider: " + mod.Name())
+	}
+	entries := p.AndroidMkEntries()
+	entries.fillInEntries(config, bpPath, mod)
+	return entries
+}
diff --git a/cc/proto_test.go b/cc/proto_test.go
index a7fcef9..4f0de78 100644
--- a/cc/proto_test.go
+++ b/cc/proto_test.go
@@ -15,7 +15,6 @@
 package cc
 
 import (
-	"runtime"
 	"strings"
 	"testing"
 
@@ -38,9 +37,6 @@
 	})
 
 	t.Run("plugin", func(t *testing.T) {
-		if runtime.GOOS != "linux" {
-			t.Skip("TODO(b/129763458): cc_binary_host tests fail on mac when trying to exec xcrun")
-		}
 		ctx := testCc(t, `
 		cc_binary_host {
 			name: "protoc-gen-foobar",
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index 2dfa546..c858c40 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -126,6 +126,7 @@
 
 var sdkVersion string
 var useVersion string
+var staticDeps bool
 var jetifier bool
 
 func InList(s string, list []string) bool {
@@ -333,6 +334,38 @@
 
 var bpTemplate = template.Must(template.New("bp").Parse(`
 {{.ImportModuleType}} {
+    name: "{{.BpName}}",
+    {{.ImportProperty}}: ["{{.ArtifactFile}}"],
+    sdk_version: "{{.SdkVersion}}",
+    {{- if .Jetifier}}
+    jetifier: true,
+    {{- end}}
+    {{- if .IsAar}}
+    min_sdk_version: "{{.MinSdkVersion}}",
+    static_libs: [
+        {{- range .BpJarDeps}}
+        "{{.}}",
+        {{- end}}
+        {{- range .BpAarDeps}}
+        "{{.}}",
+        {{- end}}
+        {{- range .BpExtraStaticLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- if .BpExtraLibs}}
+    libs: [
+        {{- range .BpExtraLibs}}
+        "{{.}}",
+        {{- end}}
+    ],
+    {{- end}}
+    {{- end}}
+}
+`))
+
+var bpDepsTemplate = template.Must(template.New("bp").Parse(`
+{{.ImportModuleType}} {
     name: "{{.BpName}}-nodeps",
     {{.ImportProperty}}: ["{{.ArtifactFile}}"],
     sdk_version: "{{.SdkVersion}}",
@@ -533,8 +566,8 @@
 	flag.Var(&hostModuleNames, "host", "Specifies that the corresponding module (specified in the form 'module.group:module.artifact') is a host module")
 	flag.StringVar(&sdkVersion, "sdk-version", "", "What to write to sdk_version")
 	flag.StringVar(&useVersion, "use-version", "", "Only read artifacts of a specific version")
+	flag.BoolVar(&staticDeps, "static-deps", false, "Statically include direct dependencies")
 	flag.BoolVar(&jetifier, "jetifier", false, "Sets jetifier: true on all modules")
-	flag.Bool("static-deps", false, "Ignored")
 	flag.StringVar(&regen, "regen", "", "Rewrite specified file")
 	flag.Parse()
 
@@ -648,7 +681,11 @@
 
 	for _, pom := range poms {
 		var err error
-		err = bpTemplate.Execute(buf, pom)
+		if staticDeps {
+			err = bpDepsTemplate.Execute(buf, pom)
+		} else {
+			err = bpTemplate.Execute(buf, pom)
+		}
 		if err != nil {
 			fmt.Fprintln(os.Stderr, "Error writing", pom.PomFile, pom.BpName(), err)
 			os.Exit(1)
diff --git a/java/androidmk.go b/java/androidmk.go
index d2e0f2e..068f7b1 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -38,7 +38,18 @@
 		}
 		fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
 		fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
-		android.WriteRequiredModulesSettings(w, data)
+		if len(data.Required) > 0 {
+			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(data.Required, " "))
+		}
+		if len(data.Host_required) > 0 {
+			fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES :=", strings.Join(data.Host_required, " "))
+		}
+		if len(data.Target_required) > 0 {
+			fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(data.Target_required, " "))
+		}
+		if r := library.deviceProperties.Target.Hostdex.Required; len(r) > 0 {
+			fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(r, " "))
+		}
 		fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
 	}
 }
@@ -83,6 +94,10 @@
 					fmt.Fprintln(w, "LOCAL_ADDITIONAL_CHECKED_MODULE +=", strings.Join(library.additionalCheckedModules.Strings(), " "))
 				}
 
+				if library.proguardDictionary != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", library.proguardDictionary.String())
+				}
+
 				// Temporary hack: export sources used to compile framework.jar to Make
 				// to be used for droiddoc
 				// TODO(ccross): remove this once droiddoc is in soong
@@ -365,9 +380,6 @@
 		if a.aarFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_AAR :=", a.aarFile.String())
 		}
-		if a.proguardDictionary != nil {
-			fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", a.proguardDictionary.String())
-		}
 
 		if a.Name() == "framework-res" {
 			fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9f40a6c..9c883e5 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -15,9 +15,12 @@
 package java
 
 import (
-	"android/soong/android"
+	"fmt"
+	"io"
 
 	"github.com/google/blueprint"
+
+	"android/soong/android"
 )
 
 type DeviceHostConverter struct {
@@ -30,6 +33,9 @@
 	implementationJars            android.Paths
 	implementationAndResourceJars android.Paths
 	resourceJars                  android.Paths
+
+	combinedHeaderJar         android.Path
+	combinedImplementationJar android.Path
 }
 
 type DeviceHostConverterProperties struct {
@@ -98,6 +104,27 @@
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
 	})
+
+	jarName := ctx.ModuleName() + ".jar"
+
+	if len(d.implementationAndResourceJars) > 1 {
+		outputFile := android.PathForModuleOut(ctx, "combined", jarName)
+		TransformJarsToJar(ctx, outputFile, "combine", d.implementationAndResourceJars,
+			android.OptionalPath{}, false, nil, nil)
+		d.combinedImplementationJar = outputFile
+	} else {
+		d.combinedImplementationJar = d.implementationAndResourceJars[0]
+	}
+
+	if len(d.headerJars) > 1 {
+		outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName)
+		TransformJarsToJar(ctx, outputFile, "turbine combine", d.headerJars,
+			android.OptionalPath{}, false, nil, nil)
+		d.combinedHeaderJar = outputFile
+	} else {
+		d.combinedHeaderJar = d.headerJars[0]
+	}
+
 }
 
 var _ Dependency = (*DeviceHostConverter)(nil)
@@ -129,3 +156,18 @@
 func (d *DeviceHostConverter) ExportedSdkLibs() []string {
 	return nil
 }
+
+func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData {
+	return android.AndroidMkData{
+		Class:      "JAVA_LIBRARIES",
+		OutputFile: android.OptionalPathForPath(d.combinedImplementationJar),
+		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+		Extra: []android.AndroidMkExtraFunc{
+			func(w io.Writer, outputFile android.Path) {
+				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", d.combinedHeaderJar.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", d.combinedImplementationJar.String())
+			},
+		},
+	}
+}
diff --git a/java/java.go b/java/java.go
index d6c759b..6168b38 100644
--- a/java/java.go
+++ b/java/java.go
@@ -221,6 +221,13 @@
 	// If true, export a copy of the module as a -hostdex module for host testing.
 	Hostdex *bool
 
+	Target struct {
+		Hostdex struct {
+			// Additional required dependencies to add to -hostdex modules.
+			Required []string
+		}
+	}
+
 	// If set to true, compile dex regardless of installable.  Defaults to false.
 	Compile_dex *bool
 
@@ -1632,6 +1639,9 @@
 		&module.Module.protoProperties,
 		&module.testHelperLibraryProperties)
 
+	module.Module.properties.Installable = proptools.BoolPtr(true)
+	module.Module.dexpreopter.isTest = true
+
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
 }