summaryrefslogtreecommitdiff
path: root/ravenwood/runtime-common-src
diff options
context:
space:
mode:
Diffstat (limited to 'ravenwood/runtime-common-src')
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java68
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java46
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java241
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java26
-rw-r--r--ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java71
5 files changed, 452 insertions, 0 deletions
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java
new file mode 100644
index 000000000000..ee280991216a
--- /dev/null
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2024 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 com.android.ravenwood.common;
+
+import java.io.FileDescriptor;
+
+/**
+ * Collection of methods to workaround limitation in the hostside JVM.
+ */
+public abstract class JvmWorkaround {
+ JvmWorkaround() {
+ }
+
+ // We only support OpenJDK for now.
+ private static JvmWorkaround sInstance =
+ RavenwoodCommonUtils.isOnRavenwood() ? new OpenJdkWorkaround() : new NullWorkaround();
+
+ public static JvmWorkaround getInstance() {
+ return sInstance;
+ }
+
+ /**
+ * Equivalent to Android's FileDescriptor.setInt$().
+ */
+ public abstract void setFdInt(FileDescriptor fd, int fdInt);
+
+
+ /**
+ * Equivalent to Android's FileDescriptor.getInt$().
+ */
+ public abstract int getFdInt(FileDescriptor fd);
+
+ /**
+ * Placeholder implementation for the host side.
+ *
+ * Even on the host side, we don't want to throw just because the class is loaded,
+ * which could cause weird random issues, so we throw from individual methods rather
+ * than from the constructor.
+ */
+ private static class NullWorkaround extends JvmWorkaround {
+ private RuntimeException calledOnHostside() {
+ throw new RuntimeException("This method shouldn't be called on the host side");
+ }
+
+ @Override
+ public void setFdInt(FileDescriptor fd, int fdInt) {
+ throw calledOnHostside();
+ }
+
+ @Override
+ public int getFdInt(FileDescriptor fd) {
+ throw calledOnHostside();
+ }
+ }
+}
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java
new file mode 100644
index 000000000000..9aedaab5b911
--- /dev/null
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 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 com.android.ravenwood.common;
+
+import java.io.FileDescriptor;
+
+class OpenJdkWorkaround extends JvmWorkaround {
+ @Override
+ public void setFdInt(FileDescriptor fd, int fdInt) {
+ try {
+ final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod(
+ "getJavaIOFileDescriptorAccess").invoke(null);
+ Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod(
+ "set", FileDescriptor.class, int.class).invoke(obj, fd, fdInt);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException("Failed to interact with raw FileDescriptor internals;"
+ + " perhaps JRE has changed?", e);
+ }
+ }
+
+ @Override
+ public int getFdInt(FileDescriptor fd) {
+ try {
+ final Object obj = Class.forName("jdk.internal.access.SharedSecrets").getMethod(
+ "getJavaIOFileDescriptorAccess").invoke(null);
+ return (int) Class.forName("jdk.internal.access.JavaIOFileDescriptorAccess").getMethod(
+ "get", FileDescriptor.class).invoke(obj, fd);
+ } catch (ReflectiveOperationException e) {
+ throw new RuntimeException("Failed to interact with raw FileDescriptor internals;"
+ + " perhaps JRE has changed?", e);
+ }
+ }
+}
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
new file mode 100644
index 000000000000..a94cab2582ca
--- /dev/null
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2024 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 com.android.ravenwood.common;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+
+public class RavenwoodCommonUtils {
+ private RavenwoodCommonUtils() {
+ }
+
+ private static final Object sLock = new Object();
+
+ /** Name of `libravenwood_runtime` */
+ private static final String RAVENWOOD_NATIVE_RUNTIME_NAME = "ravenwood_runtime";
+
+ /** Directory name of `out/host/linux-x86/testcases/ravenwood-runtime` */
+ private static final String RAVENWOOD_RUNTIME_DIR_NAME = "ravenwood-runtime";
+
+ private static boolean sEnableExtraRuntimeCheck =
+ "1".equals(System.getenv("RAVENWOOD_ENABLE_EXTRA_RUNTIME_CHECK"));
+
+ private static final boolean IS_ON_RAVENWOOD = isOnRavenwoodInternal();
+
+ private static final String RAVEWOOD_RUNTIME_PATH = getRavenwoodRuntimePathInternal();
+
+ /**
+ * @return if we're running on Ravenwood.
+ */
+ public static boolean isOnRavenwood() {
+ return IS_ON_RAVENWOOD;
+ }
+
+ private static boolean isOnRavenwoodInternal() {
+ // Call RavenwoodEnvironment.getInstance().isRunningOnRavenwood(),
+ // but here we can't use Android APIs directly, so use reflections.
+ try {
+ var clazz = Class.forName("com.android.internal.ravenwood.RavenwoodEnvironment");
+ var getInstance = clazz.getMethod("getInstance");
+ var isRunningOnRavenwood = clazz.getMethod("isRunningOnRavenwood");
+
+ var instance = getInstance.invoke(null);
+ return (boolean) isRunningOnRavenwood.invoke(instance);
+
+ } catch (Exception e) {
+ throw new RuntimeException("Can't access RavenwoodEnvironment", e);
+ }
+ }
+
+ /**
+ * Throws if the runtime is not Ravenwood.
+ */
+ public static void ensureOnRavenwood() {
+ if (!isOnRavenwood()) {
+ throw new RavenwoodRuntimeException("This is only supposed to be used on Ravenwood");
+ }
+ }
+
+ /**
+ * @return if the various extra runtime check should be enabled.
+ */
+ public static boolean shouldEnableExtraRuntimeCheck() {
+ return sEnableExtraRuntimeCheck;
+ }
+
+ /**
+ * Load the main runtime JNI library.
+ */
+ public static void loadRavenwoodNativeRuntime() {
+ ensureOnRavenwood();
+ loadJniLibrary(RAVENWOOD_NATIVE_RUNTIME_NAME);
+ }
+
+ /**
+ * Internal implementation of
+ * {@link android.platform.test.ravenwood.RavenwoodUtils#loadJniLibrary(String)}
+ */
+ public static void loadJniLibrary(String libname) {
+ if (RavenwoodCommonUtils.isOnRavenwood()) {
+ loadJniLibraryInternal(libname);
+ } else {
+ System.loadLibrary(libname);
+ }
+ }
+
+ /**
+ * Function equivalent to ART's System.loadLibrary. See RavenwoodUtils for why we need it.
+ */
+ private static void loadJniLibraryInternal(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 + " not found in "
+ + "java.library.path: " + path);
+ } catch (Throwable 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, "");
+ }
+ }
+
+ var gparent = new File("../..").getCanonicalFile();
+ out.println("# ../..=" + gparent);
+ 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 + " ");
+ }
+ }
+ }
+
+ /**
+ * @return the full directory path that contains the "ravenwood-runtime" files.
+ *
+ * This method throws if called on the device side.
+ */
+ public static String getRavenwoodRuntimePath() {
+ ensureOnRavenwood();
+ return RAVEWOOD_RUNTIME_PATH;
+ }
+
+ private static String getRavenwoodRuntimePathInternal() {
+ if (!isOnRavenwood()) {
+ return null;
+ }
+ var path = System.getProperty("java.library.path");
+
+ System.out.println("Looking for " + RAVENWOOD_RUNTIME_DIR_NAME + " directory"
+ + " in java.library.path:" + path);
+
+ try {
+ if (path == null) {
+ throw new IllegalStateException("java.library.path shouldn't be null");
+ }
+ for (var dir : path.split(":")) {
+
+ // For each path, see if the path contains RAVENWOOD_RUNTIME_DIR_NAME.
+ var d = new File(dir);
+ for (;;) {
+ if (d.getParent() == null) {
+ break; // Root dir, stop.
+ }
+ if (RAVENWOOD_RUNTIME_DIR_NAME.equals(d.getName())) {
+ var ret = d.getAbsolutePath() + "/";
+ System.out.println("Found: " + ret);
+ return ret;
+ }
+ d = d.getParentFile();
+ }
+ }
+ throw new IllegalStateException(RAVENWOOD_RUNTIME_DIR_NAME + " not found");
+ } catch (Throwable e) {
+ dumpFiles(System.out);
+ throw e;
+ }
+ }
+
+ /** Close an {@link AutoCloseable}. */
+ public static void closeQuietly(AutoCloseable c) {
+ if (c != null) {
+ try {
+ c.close();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+
+ /** Close a {@link FileDescriptor}. */
+ public static void closeQuietly(FileDescriptor fd) {
+ var is = new FileInputStream(fd);
+ RavenwoodCommonUtils.closeQuietly(is);
+ }
+}
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java
new file mode 100644
index 000000000000..7b0cebcecc1a
--- /dev/null
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 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 com.android.ravenwood.common;
+
+public class RavenwoodRuntimeException extends RuntimeException {
+ public RavenwoodRuntimeException(String message) {
+ super(message);
+ }
+
+ public RavenwoodRuntimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java
new file mode 100644
index 000000000000..65402219ebee
--- /dev/null
+++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodRuntimeNative.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2024 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 com.android.ravenwood.common;
+
+import java.io.FileDescriptor;
+
+/**
+ * Class to host all the JNI methods used in ravenwood runtime.
+ */
+public class RavenwoodRuntimeNative {
+ private RavenwoodRuntimeNative() {
+ }
+
+ static {
+ RavenwoodCommonUtils.ensureOnRavenwood();
+ RavenwoodCommonUtils.loadRavenwoodNativeRuntime();
+ }
+
+ public static native void applyFreeFunction(long freeFunction, long nativePtr);
+
+ public static native long nLseek(int fd, long offset, int whence);
+
+ public static native int[] nPipe2(int flags);
+
+ public static native int nDup(int oldfd);
+
+ public static native int nFcntlInt(int fd, int cmd, int arg);
+
+ public static long lseek(FileDescriptor fd, long offset, int whence) {
+ return nLseek(JvmWorkaround.getInstance().getFdInt(fd), offset, whence);
+ }
+
+ public static FileDescriptor[] pipe2(int flags) {
+ var fds = nPipe2(flags);
+ var ret = new FileDescriptor[] {
+ new FileDescriptor(),
+ new FileDescriptor(),
+ };
+ JvmWorkaround.getInstance().setFdInt(ret[0], fds[0]);
+ JvmWorkaround.getInstance().setFdInt(ret[1], fds[1]);
+
+ return ret;
+ }
+
+ public static FileDescriptor dup(FileDescriptor fd) {
+ var fdInt = nDup(JvmWorkaround.getInstance().getFdInt(fd));
+
+ var retFd = new java.io.FileDescriptor();
+ JvmWorkaround.getInstance().setFdInt(retFd, fdInt);
+ return retFd;
+ }
+
+ public static int fcntlInt(FileDescriptor fd, int cmd, int arg) {
+ var fdInt = JvmWorkaround.getInstance().getFdInt(fd);
+
+ return nFcntlInt(fdInt, cmd, arg);
+ }
+}