Split java_binary modules into common and binary variants

Add a common_first multilib type and use it for java.Binary
so that the java part is compiled as a "common" arch type
but the wrapper script is installed as a "linux_glibc" arch
type.  This allows java_binary to be used as a tool dependency
for a genrule.

Bug: 68397812
Test: TestJavaBinary
Change-Id: I809060839ce8878300da3fb76426ceb1ea6b0e8e
diff --git a/java/androidmk.go b/java/androidmk.go
index 2e67639..f52d5e9 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -95,28 +95,35 @@
 }
 
 func (binary *Binary) AndroidMk() android.AndroidMkData {
-	return android.AndroidMkData{
-		Class:      "JAVA_LIBRARIES",
-		OutputFile: android.OptionalPathForPath(binary.implementationJarFile),
-		Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
-		Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
-			android.WriteAndroidMkData(w, data)
 
-			fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
-			fmt.Fprintln(w, "include $(CLEAR_VARS)")
-			fmt.Fprintln(w, "LOCAL_MODULE := "+name)
-			fmt.Fprintln(w, "LOCAL_MODULE_CLASS := EXECUTABLES")
-			if strings.Contains(prefix, "HOST_") {
-				fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
-			}
-			fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
-			fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", binary.wrapperFile.String())
-			fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+	if !binary.isWrapperVariant {
+		return android.AndroidMkData{
+			Class:      "JAVA_LIBRARIES",
+			OutputFile: android.OptionalPathForPath(binary.implementationJarFile),
+			Include:    "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+				android.WriteAndroidMkData(w, data)
 
-			// Ensure that the wrapper script timestamp is always updated when the jar is updated
-			fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
-			fmt.Fprintln(w, "jar_installed_module :=")
-		},
+				fmt.Fprintln(w, "jar_installed_module := $(LOCAL_INSTALLED_MODULE)")
+			},
+		}
+	} else {
+		return android.AndroidMkData{
+			Class:      "EXECUTABLES",
+			OutputFile: android.OptionalPathForPath(binary.wrapperFile),
+			Extra: []android.AndroidMkExtraFunc{
+				func(w io.Writer, outputFile android.Path) {
+					fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+				},
+			},
+			Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
+				android.WriteAndroidMkData(w, data)
+
+				// Ensure that the wrapper script timestamp is always updated when the jar is updated
+				fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): $(jar_installed_module)")
+				fmt.Fprintln(w, "jar_installed_module :=")
+			},
+		}
 	}
 }
 
diff --git a/java/java.go b/java/java.go
index 0a47db0..0e54e3c 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1014,6 +1014,8 @@
 
 	binaryProperties binaryProperties
 
+	isWrapperVariant bool
+
 	wrapperFile android.SourcePath
 	binaryFile  android.OutputPath
 }
@@ -1023,21 +1025,32 @@
 }
 
 func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.Library.GenerateAndroidBuildActions(ctx)
-
-	// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
-	// another build rule before the jar has been installed.
-	if String(j.binaryProperties.Wrapper) != "" {
-		j.wrapperFile = android.PathForModuleSrc(ctx, String(j.binaryProperties.Wrapper)).SourcePath
+	if ctx.Arch().ArchType == android.Common {
+		// Compile the jar
+		j.Library.GenerateAndroidBuildActions(ctx)
 	} else {
-		j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+		// Handle the binary wrapper
+		j.isWrapperVariant = true
+
+		if String(j.binaryProperties.Wrapper) != "" {
+			j.wrapperFile = android.PathForModuleSrc(ctx, String(j.binaryProperties.Wrapper)).SourcePath
+		} else {
+			j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
+		}
+
+		// Depend on the installed jar so that the wrapper doesn't get executed by
+		// another build rule before the jar has been installed.
+		jarFile := ctx.PrimaryModule().(*Binary).installFile
+
+		j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
+			ctx.ModuleName(), j.wrapperFile, jarFile)
 	}
-	j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
-		ctx.ModuleName(), j.wrapperFile, j.installFile)
 }
 
 func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	j.deps(ctx)
+	if ctx.Arch().ArchType == android.Common {
+		j.deps(ctx)
+	}
 }
 
 func BinaryFactory() android.Module {
@@ -1049,7 +1062,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
-	InitJavaModule(module, android.HostAndDeviceSupported)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommonFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
@@ -1062,7 +1076,8 @@
 		&module.Module.protoProperties,
 		&module.binaryProperties)
 
-	InitJavaModule(module, android.HostSupported)
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommonFirst)
+	android.InitDefaultableModule(module)
 	return module
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index 58b27c3..78fbd41 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -62,6 +62,7 @@
 
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
+	ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
 	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory(true)))
 	ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
 	ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(ImportFactory))
@@ -147,6 +148,8 @@
 		// For framework-res, which is an implicit dependency for framework
 		"AndroidManifest.xml":                   nil,
 		"build/target/product/security/testkey": nil,
+
+		"build/soong/scripts/jar-wrapper.sh": nil,
 	}
 
 	for k, v := range fs {
@@ -159,6 +162,7 @@
 }
 
 func run(t *testing.T, ctx *android.TestContext, config android.Config) {
+	t.Helper()
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	fail(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
@@ -166,6 +170,7 @@
 }
 
 func testJava(t *testing.T, bp string) *android.TestContext {
+	t.Helper()
 	config := testConfig(nil)
 	ctx := testContext(config, bp, nil)
 	run(t, ctx, config)
@@ -250,6 +255,35 @@
 	}
 }
 
+func TestBinary(t *testing.T) {
+	ctx := testJava(t, `
+		java_library_host {
+			name: "foo",
+			srcs: ["a.java"],
+		}
+
+		java_binary_host {
+			name: "bar",
+			srcs: ["b.java"],
+			static_libs: ["foo"],
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+
+	bar := ctx.ModuleForTests("bar", buildOS+"_common")
+	barJar := bar.Output("bar.jar").Output.String()
+	barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
+	barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
+
+	// Test that the install binary wrapper depends on the installed jar file
+	if len(barWrapperDeps) != 1 || barWrapperDeps[0] != barJar {
+		t.Errorf("expected binary wrapper implicits [%q], got %v",
+			barJar, barWrapperDeps)
+	}
+
+}
+
 var classpathTestcases = []struct {
 	name          string
 	moduleType    string
@@ -831,6 +865,7 @@
 }
 
 func fail(t *testing.T, errs []error) {
+	t.Helper()
 	if len(errs) > 0 {
 		for _, err := range errs {
 			t.Error(err)