Reland: Add jni_libs property to java tests

Add jni_libs property to java tests and treat it as test data that
should be copied to the lib or lib64 directory in the test directory.

This relands I3a118b933ab30dcd731c6dc2708da9bc63ab5520 with fixes for
the test on mac.

Fixes: 176593487
Test: java_test.go
Change-Id: I2f8c46643cff7a7ae6dc4d4dbad58f0396e45f09
diff --git a/java/java.go b/java/java.go
index ee4f2eb..adb0c56 100644
--- a/java/java.go
+++ b/java/java.go
@@ -27,6 +27,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/cc"
 	"android/soong/dexpreopt"
 	"android/soong/java/config"
 	"android/soong/tradefed"
@@ -708,6 +709,9 @@
 
 	// Test options.
 	Test_options TestOptions
+
+	// Names of modules containing JNI libraries that should be installed alongside the test.
+	Jni_libs []string
 }
 
 type hostTestProperties struct {
@@ -769,6 +773,13 @@
 		}
 	}
 
+	if len(j.testProperties.Jni_libs) > 0 {
+		for _, target := range ctx.MultiTargets() {
+			sharedLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
+			ctx.AddFarVariationDependencies(sharedLibVariations, jniLibTag, j.testProperties.Jni_libs...)
+		}
+	}
+
 	j.deps(ctx)
 }
 
@@ -793,6 +804,29 @@
 		j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
 	})
 
+	ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) {
+		sharedLibInfo := ctx.OtherModuleProvider(dep, cc.SharedLibraryInfoProvider).(cc.SharedLibraryInfo)
+		if sharedLibInfo.SharedLibrary != nil {
+			// Copy to an intermediate output directory to append "lib[64]" to the path,
+			// so that it's compatible with the default rpath values.
+			var relPath string
+			if sharedLibInfo.Target.Arch.ArchType.Multilib == "lib64" {
+				relPath = filepath.Join("lib64", sharedLibInfo.SharedLibrary.Base())
+			} else {
+				relPath = filepath.Join("lib", sharedLibInfo.SharedLibrary.Base())
+			}
+			relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath)
+			ctx.Build(pctx, android.BuildParams{
+				Rule:   android.Cp,
+				Input:  sharedLibInfo.SharedLibrary,
+				Output: relocatedLib,
+			})
+			j.data = append(j.data, relocatedLib)
+		} else {
+			ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+		}
+	})
+
 	j.Library.GenerateAndroidBuildActions(ctx)
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index 0523458..e7ea4ef 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,6 +20,7 @@
 	"path/filepath"
 	"reflect"
 	"regexp"
+	"runtime"
 	"strconv"
 	"strings"
 	"testing"
@@ -462,6 +463,38 @@
 	}
 }
 
+func TestTest(t *testing.T) {
+	ctx, _ := testJava(t, `
+		java_test_host {
+			name: "foo",
+			srcs: ["a.java"],
+			jni_libs: ["libjni"],
+		}
+
+		cc_library_shared {
+			name: "libjni",
+			host_supported: true,
+			device_supported: false,
+			stl: "none",
+		}
+	`)
+
+	buildOS := android.BuildOs.String()
+
+	foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
+
+	expected := "lib64/libjni.so"
+	if runtime.GOOS == "darwin" {
+		expected = "lib64/libjni.dylib"
+	}
+
+	fooTestData := foo.data
+	if len(fooTestData) != 1 || fooTestData[0].Rel() != expected {
+		t.Errorf(`expected foo test data relative path [%q], got %q`,
+			expected, fooTestData.Strings())
+	}
+}
+
 func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
 	bp := `
 		java_library {