Add `data_native_bins` property to java_test_host

When multiple os/arch variants are supported, java_test_host could not
find a matching arch due to java having arch:common, whereas native
binaries support a specific architecture. This change adds the property
`data_native_bins` in order to support binaries with the appropriate
os/arch variants.

Test: m FirmwareDtboVerification with data_native_bins
Test: forrest
Bug: 153848038
Change-Id: I45adebff0fde2811d5ef5620c697b97b768c951f
diff --git a/java/Android.bp b/java/Android.bp
index fd06c46..e345014 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -10,6 +10,7 @@
         "soong-dexpreopt",
         "soong-genrule",
         "soong-java-config",
+        "soong-python",
         "soong-remoteexec",
         "soong-tradefed",
     ],
diff --git a/java/java.go b/java/java.go
index ef9613d..bd476bc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -556,7 +556,20 @@
 }
 
 func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
-	android.InitAndroidArchModule(module, hod, android.MultilibCommon)
+	initJavaModule(module, hod, false)
+}
+
+func InitJavaModuleMultiTargets(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
+	initJavaModule(module, hod, true)
+}
+
+func initJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported, multiTargets bool) {
+	multilib := android.MultilibCommon
+	if multiTargets {
+		android.InitAndroidMultiTargetsArchModule(module, hod, multilib)
+	} else {
+		android.InitAndroidArchModule(module, hod, multilib)
+	}
 	android.InitDefaultableModule(module)
 }
 
@@ -575,6 +588,7 @@
 }
 
 var (
+	dataNativeBinsTag     = dependencyTag{name: "dataNativeBins"}
 	staticLibTag          = dependencyTag{name: "staticlib"}
 	libTag                = dependencyTag{name: "javalib"}
 	java9LibTag           = dependencyTag{name: "java9lib"}
@@ -2193,6 +2207,11 @@
 	Test_mainline_modules []string
 }
 
+type hostTestProperties struct {
+	// list of native binary modules that should be installed alongside the test
+	Data_native_bins []string `android:"arch_variant"`
+}
+
 type testHelperLibraryProperties struct {
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
@@ -2218,6 +2237,12 @@
 	data       android.Paths
 }
 
+type TestHost struct {
+	Test
+
+	testHostProperties hostTestProperties
+}
+
 type TestHelperLibrary struct {
 	Library
 
@@ -2232,11 +2257,26 @@
 	testConfig android.Path
 }
 
+func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if len(j.testHostProperties.Data_native_bins) > 0 {
+		for _, target := range ctx.MultiTargets() {
+			ctx.AddVariationDependencies(target.Variations(), dataNativeBinsTag, j.testHostProperties.Data_native_bins...)
+		}
+	}
+
+	j.deps(ctx)
+}
+
 func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
 		j.testProperties.Test_suites, j.testProperties.Auto_gen_config)
+
 	j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
 
+	ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) {
+		j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
+	})
+
 	j.Library.GenerateAndroidBuildActions(ctx)
 }
 
@@ -2377,14 +2417,15 @@
 // A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were
 // compiled against the host bootclasspath.
 func TestHostFactory() android.Module {
-	module := &Test{}
+	module := &TestHost{}
 
 	module.addHostProperties()
 	module.AddProperties(&module.testProperties)
+	module.AddProperties(&module.testHostProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
-	InitJavaModule(module, android.HostSupported)
+	InitJavaModuleMultiTargets(module, android.HostSupported)
 	return module
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index db3f187..73e6792 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -31,6 +31,7 @@
 	"android/soong/cc"
 	"android/soong/dexpreopt"
 	"android/soong/genrule"
+	"android/soong/python"
 )
 
 var buildDir string
@@ -81,6 +82,7 @@
 	ctx.RegisterModuleType("java_plugin", PluginFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+	ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory)
 	RegisterDocsBuildComponents(ctx)
 	RegisterStubsBuildComponents(ctx)
 	RegisterSdkLibraryBuildComponents(ctx)
@@ -89,6 +91,7 @@
 
 	RegisterPrebuiltApisBuildComponents(ctx)
 
+	ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators)
 	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
 	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
 	ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
@@ -2008,3 +2011,28 @@
 		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
 	}
 }
+
+func TestDataNativeBinaries(t *testing.T) {
+	ctx, config := testJava(t, `
+		java_test_host {
+			name: "foo",
+			srcs: ["a.java"],
+			data_native_bins: ["bin"]
+		}
+
+		python_binary_host {
+			name: "bin",
+			srcs: ["bin.py"],
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+
+	test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
+	entries := android.AndroidMkEntriesForTest(t, config, "", test)[0]
+	expected := []string{buildDir + "/.intermediates/bin/" + buildOS + "_x86_64_PY3/bin:bin"}
+	actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+	if !reflect.DeepEqual(expected, actual) {
+		t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual)
+	}
+}
diff --git a/java/testing.go b/java/testing.go
index e761743..1e725fa 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -22,6 +22,8 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/python"
+
 	"github.com/google/blueprint"
 )
 
@@ -85,6 +87,10 @@
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":                nil,
 		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
 
+		"bin.py": nil,
+		python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
+		MAIN_FILE = '%main%'`),
+
 		// For java_sdk_library
 		"api/module-lib-current.txt":                        nil,
 		"api/module-lib-removed.txt":                        nil,
diff --git a/python/binary.go b/python/binary.go
index 695fa12..5a74926 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -65,7 +65,7 @@
 }
 
 var (
-	stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
+	StubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
 )
 
 func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
diff --git a/python/builder.go b/python/builder.go
index 36baecd..dc2d1f1 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -91,7 +91,7 @@
 
 	if !embeddedLauncher {
 		// the path of stub_template_host.txt from source tree.
-		template := android.PathForSource(ctx, stubTemplateHost)
+		template := android.PathForSource(ctx, StubTemplateHost)
 		implicits = append(implicits, template)
 
 		// intermediate output path for __main__.py
diff --git a/python/python.go b/python/python.go
index a6c9e2a..479c729 100644
--- a/python/python.go
+++ b/python/python.go
@@ -30,9 +30,11 @@
 )
 
 func init() {
-	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-		ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
-	})
+	android.PreDepsMutators(RegisterPythonPreDepsMutators)
+}
+
+func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) {
+	ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
 }
 
 // the version properties that apply to python libraries and binaries.
@@ -226,15 +228,20 @@
 	return func(mctx android.BottomUpMutatorContext) {
 		if base, ok := mctx.Module().(*Module); ok {
 			versionNames := []string{}
-			if base.properties.Version.Py2.Enabled != nil &&
-				*(base.properties.Version.Py2.Enabled) == true {
-				versionNames = append(versionNames, pyVersion2)
-			}
+			// PY3 is first so that we alias the PY3 variant rather than PY2 if both
+			// are available
 			if !(base.properties.Version.Py3.Enabled != nil &&
 				*(base.properties.Version.Py3.Enabled) == false) {
 				versionNames = append(versionNames, pyVersion3)
 			}
+			if base.properties.Version.Py2.Enabled != nil &&
+				*(base.properties.Version.Py2.Enabled) == true {
+				versionNames = append(versionNames, pyVersion2)
+			}
 			modules := mctx.CreateVariations(versionNames...)
+			if len(versionNames) > 0 {
+				mctx.AliasVariation(versionNames[0])
+			}
 			for i, v := range versionNames {
 				// set the actual version for Python module.
 				modules[i].(*Module).properties.Actual_version = v
diff --git a/python/python_test.go b/python/python_test.go
index 1245ca1..23db24e 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -301,7 +301,7 @@
 				filepath.Join("dir", "file2.py"):       nil,
 				filepath.Join("dir", "bin.py"):         nil,
 				filepath.Join("dir", "file4.py"):       nil,
-				stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
+				StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
 				MAIN_FILE = '%main%'`),
 			},
 			expectedBinaries: []pyModule{
@@ -330,9 +330,7 @@
 		t.Run(d.desc, func(t *testing.T) {
 			config := android.TestConfig(buildDir, nil, "", d.mockFiles)
 			ctx := android.NewTestContext()
-			ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
-				ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
-			})
+			ctx.PreDepsMutators(RegisterPythonPreDepsMutators)
 			ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
 			ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
 			ctx.RegisterModuleType("python_defaults", defaultsFactory)