summaryrefslogtreecommitdiff
path: root/ravenwood/junit-src
diff options
context:
space:
mode:
author Makoto Onuki <omakoto@google.com> 2024-02-01 15:34:37 -0800
committer Makoto Onuki <omakoto@google.com> 2024-02-12 14:22:10 -0800
commitbe841eded00fc882678a395ee66e1242158dd969 (patch)
tree35b77389684054267096e6dd5aa2a6b0a6846463 /ravenwood/junit-src
parent8e4eb7ed4d16c7ea847d5e21717389db8dd021de (diff)
Adding test for loading JNI libraries in individual tests
Add a bivalent test that uses a native library. Also added a utility method to load it in the same way on both sides. Bug: 318393625 Bug: 323931246 Test: run-ravenwood-tests.sh Test: atest RavenwoodBivalentTest_device Change-Id: I270058c15f718ff20640681742035e33e5e015a1
Diffstat (limited to 'ravenwood/junit-src')
-rw-r--r--ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java127
1 files changed, 127 insertions, 0 deletions
diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
new file mode 100644
index 000000000000..b736a7662bd4
--- /dev/null
+++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * 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 android.platform.test.ravenwood;
+
+import java.io.File;
+import java.io.PrintStream;
+import java.util.Arrays;
+
+/**
+ * Utilities for writing (bivalent) ravenwood tests.
+ */
+public class RavenwoodUtils {
+ private RavenwoodUtils() {
+ }
+
+ /**
+ * Load a JNI library respecting {@code java.library.path}
+ * (which reflects {@code LD_LIBRARY_PATH}).
+ *
+ * <p>{@code libname} must be the library filename without:
+ * - directory
+ * - "lib" prefix
+ * - and the ".so" extension
+ *
+ * <p>For example, in order to load "libmyjni.so", then pass "myjni".
+ *
+ * <p>This is basically the same thing as Java's {@link System#loadLibrary(String)},
+ * but this API works slightly different on ART and on the desktop Java, namely
+ * the desktop Java version uses a different entry point method name
+ * {@code JNI_OnLoad_libname()} (note the included "libname")
+ * while ART always seems to use {@code JNI_OnLoad()}.
+ *
+ * <p>This method provides the same behavior on both the device side and on Ravenwood --
+ * it uses {@code JNI_OnLoad()} as the entry point name on both.
+ */
+ public static void loadJniLibrary(String libname) {
+ if (RavenwoodRule.isOnRavenwood()) {
+ loadLibraryOnRavenwood(libname);
+ } else {
+ // Just delegate to the loadLibrary().
+ System.loadLibrary(libname);
+ }
+ }
+
+ private static void loadLibraryOnRavenwood(String libname) {
+ var path = System.getProperty("java.library.path");
+ var filename = "lib" + libname + ".so";
+
+ System.out.println("Looking for library " + libname + ".so in java.library.path:" + path);
+
+ try {
+ if (path == null) {
+ throw new UnsatisfiedLinkError("Cannot load library " + libname + "."
+ + " Property java.library.path not set!");
+ }
+ for (var dir : path.split(":")) {
+ var file = new File(dir + "/" + filename);
+ if (file.exists()) {
+ System.load(file.getAbsolutePath());
+ return;
+ }
+ }
+ throw new UnsatisfiedLinkError("Library " + libname + " no found in "
+ + "java.library.path: " + path);
+ } catch (Exception e) {
+ dumpFiles(System.out);
+ throw e;
+ }
+ }
+
+ private static void dumpFiles(PrintStream out) {
+ try {
+ var path = System.getProperty("java.library.path");
+ out.println("# java.library.path=" + path);
+
+ for (var dir : path.split(":")) {
+ listFiles(out, new File(dir), "");
+
+ var gparent = new File((new File(dir)).getAbsolutePath() + "../../..")
+ .getCanonicalFile();
+ if (gparent.getName().contains("testcases")) {
+ // Special case: if we found this directory, dump its contents too.
+ listFiles(out, gparent, "");
+ }
+ }
+ } catch (Throwable th) {
+ out.println("Error: " + th.toString());
+ th.printStackTrace(out);
+ }
+ }
+
+ private static void listFiles(PrintStream out, File dir, String prefix) {
+ if (!dir.isDirectory()) {
+ out.println(prefix + dir.getAbsolutePath() + " is not a directory!");
+ return;
+ }
+ out.println(prefix + ":" + dir.getAbsolutePath() + "/");
+ // First, list the files.
+ for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) {
+ out.println(prefix + " " + file.getName() + "" + (file.isDirectory() ? "/" : ""));
+ }
+
+ // Then recurse.
+ if (dir.getAbsolutePath().startsWith("/usr") || dir.getAbsolutePath().startsWith("/lib")) {
+ // There would be too many files, so don't recurse.
+ return;
+ }
+ for (var file : Arrays.stream(dir.listFiles()).sorted().toList()) {
+ if (file.isDirectory()) {
+ listFiles(out, file, prefix + " ");
+ }
+ }
+ }
+}