source "$BR2_EXTERNAL_OPENJDK_PATH/package/openjdk-hello-world/Config.in"
+source "$BR2_EXTERNAL_OPENJDK_PATH/package/openjdk-jni-test/Config.in"
--- /dev/null
+config BR2_PACKAGE_OPENJDK_JNI_TEST
+ bool "openjdk JNI test"
+ depends on BR2_PACKAGE_OPENJDK
+ help
+ Tests openjdk JNI support
--- /dev/null
+public class JniHelper
+{
+ public void HelloManagedWorld()
+ {
+ stringMember = "Hello, Managed World";
+ }
+
+ public String stringMember = "Set from Java";
+}
--- /dev/null
+public class JniTest
+{
+ private static void Test(
+ String name,
+ Object actual,
+ Object expected,
+ String actualAsString,
+ String expectedAsString)
+ {
+ if (!actual.equals(expected))
+ {
+ System.out.println(String.format(
+ "Test: %s failed\nExpected: \"%s\", Actual: \"%s\"",
+ name,
+ expected,
+ actual));
+ JniTest.exitCode = -1;
+ }
+ else
+ {
+ System.out.println(String.format("Test: %s passed", name));
+ }
+ }
+
+ private static void Test(
+ String name,
+ String actual,
+ String expected)
+ {
+ JniTest.Test(name, actual, expected, actual, expected);
+ }
+
+ public static void main(String[] args)
+ {
+ var actualVersion = JniWrapper.get_jni_version();
+ var expectedVersion = 0x000A0000;
+ JniTest.Test(
+ "Get JNI Version",
+ actualVersion,
+ expectedVersion,
+ String.format("0x%08X", actualVersion),
+ String.format("0x%08X", expectedVersion));
+
+ JniTest.Test(
+ "Read Native String Constant",
+ JniWrapper.read_constant_string(),
+ "Hello from C");
+
+ JniTest.Test(
+ "Write Java String to Native Library",
+ JniWrapper.write_string("Hello from Java"),
+ "Hello from Java");
+
+ JniTest.Test(
+ "Write Java Char Array to Native Library",
+ JniWrapper.write_char_array("Hello from Java".toCharArray()),
+ "Hello from Java");
+
+ var helper = new JniHelper();
+ JniTest.Test(
+ "Write String Member to Native Library",
+ JniWrapper.write_string_member(helper),
+ "Set from Java");
+
+ JniWrapper.set_string_member(helper);
+ JniTest.Test(
+ "Set String Member from Native Library",
+ helper.stringMember,
+ "Set from C");
+
+ JniWrapper.execute_java_function(helper);
+ JniTest.Test(
+ "Execeute Java Function from Native Library",
+ helper.stringMember,
+ "Hello, Managed World");
+
+ helper = JniWrapper.instantiate_java_class();
+ JniTest.Test(
+ "Instantiate Java Class",
+ helper.stringMember,
+ "Instantiated from C");
+
+ JniTest.Test(
+ "Call Native Library to Set System Time",
+ JniWrapper.set_and_write_time_in_seconds(1000),
+ "1000");
+
+ System.exit(exitCode);
+ }
+
+ public static int exitCode = 0;
+}
--- /dev/null
+#include "JniWrapper.h"
+#include "jni_helper.h"
+
+// Proxies the generated function calls to the jni_helper
+
+JNIEXPORT jint JNICALL Java_JniWrapper_get_1jni_1version
+ (JNIEnv* env, jclass class)
+{
+ return get_jni_version(env);
+}
+JNIEXPORT jstring JNICALL Java_JniWrapper_read_1constant_1string
+ (JNIEnv* env, jclass class)
+{
+ return read_constant_jstring(env);
+}
+JNIEXPORT jstring JNICALL Java_JniWrapper_write_1string
+ (JNIEnv* env, jclass class, jstring string)
+{
+ return write_jstring(env, string);
+}
+JNIEXPORT jstring JNICALL Java_JniWrapper_write_1char_1array
+ (JNIEnv* env, jclass class, jcharArray chars)
+{
+ return write_jchar_array(env, chars);
+}
+JNIEXPORT jstring JNICALL Java_JniWrapper_write_1string_1member
+ (JNIEnv* env, jclass class, jobject helper)
+{
+ return write_string_member(env, helper);
+}
+JNIEXPORT void JNICALL Java_JniWrapper_set_1string_1member
+ (JNIEnv* env, jclass class, jobject helper)
+{
+ set_string_member(env, helper);
+}
+JNIEXPORT void JNICALL Java_JniWrapper_execute_1java_1function
+ (JNIEnv* env, jclass class, jobject helper)
+{
+ execute_java_function(env, helper);
+}
+JNIEXPORT jobject JNICALL Java_JniWrapper_instantiate_1java_1class
+ (JNIEnv* env, jclass class)
+{
+ return instantiate_java_class(env);
+}
+JNIEXPORT jstring JNICALL Java_JniWrapper_set_1and_1write_1time_1in_1seconds
+ (JNIEnv* env, jclass class, jint seconds)
+{
+ return set_and_write_time_in_seconds(env, seconds);
+}
--- /dev/null
+public class JniWrapper
+{
+ static
+ {
+ System.loadLibrary("jni_native");
+ }
+
+ public static native int get_jni_version();
+ public static native String read_constant_string();
+ public static native String write_string(String string);
+ public static native String write_char_array(char[] string);
+ public static native String write_string_member(JniHelper helper);
+ public static native void set_string_member(JniHelper helper);
+ public static native void execute_java_function(JniHelper helper);
+ public static native JniHelper instantiate_java_class();
+ public static native String set_and_write_time_in_seconds(int seconds);
+}
--- /dev/null
+#include "jni_helper.h"
+#include "native.h"
+
+// Handles Java/C interop
+
+jint get_jni_version(JNIEnv* env)
+{
+ return (*env)->GetVersion(env);
+}
+jstring read_constant_jstring(JNIEnv* env)
+{
+ return (*env)->NewStringUTF(env, read_constant_string());
+}
+static jstring read_internal_string_as_jstring(JNIEnv* env)
+{
+ return (*env)->NewStringUTF(env, read_internal_string());
+}
+jstring write_jstring(JNIEnv* env, jstring string)
+{
+ const char* utf8_string = (*env)->GetStringUTFChars(env, string, NULL);
+ write_internal_string(utf8_string);
+
+ (*env)->ReleaseStringUTFChars(env, string, utf8_string);
+ return read_internal_string_as_jstring(env);
+}
+jstring write_jchar_array(JNIEnv* env, jcharArray chars)
+{
+ jsize length = (*env)->GetArrayLength(env, chars);
+ jchar* body = (*env)->GetCharArrayElements(env, chars, NULL);
+ jstring input = (*env)->NewString(env, body, length);
+ jstring output = write_jstring(env, input);
+
+ (*env)->ReleaseCharArrayElements(env, chars, body, JNI_ABORT);
+ return output;
+}
+static jfieldID get_string_member_field(JNIEnv* env, jobject helper)
+{
+ jclass class = (*env)->GetObjectClass(env, helper);
+ return (*env)->GetFieldID(env, class, "stringMember", "Ljava/lang/String;");
+}
+jstring write_string_member(JNIEnv* env, jobject helper)
+{
+ jfieldID fieldID = get_string_member_field(env, helper);
+ jstring string = (*env)->GetObjectField(env, helper, fieldID);
+
+ return write_jstring(env, string);
+}
+static void set_string_member_helper(JNIEnv* env, jobject helper, const char* utf8_string)
+{
+ jfieldID fieldID = get_string_member_field(env, helper);
+ jstring string = (*env)->NewStringUTF(env, utf8_string);
+ (*env)->SetObjectField(env, helper, fieldID, string);
+}
+void set_string_member(JNIEnv* env, jobject helper)
+{
+ char stringBuffer[256];
+ write_external_string(stringBuffer, 256);
+ set_string_member_helper(env, helper, stringBuffer);
+}
+
+typedef struct
+{
+ JNIEnv* env;
+ jobject object;
+ jmethodID methodID;
+} method_parameters;
+static void call_void_java_method(void* context)
+{
+ method_parameters* parameters = (method_parameters*)context;
+ (*parameters->env)->CallVoidMethod(parameters->env, parameters->object, parameters->methodID);
+}
+void execute_java_function(JNIEnv* env, jobject helper)
+{
+ jclass class = (*env)->GetObjectClass(env, helper);
+ jmethodID methodID = (*env)->GetMethodID(env, class, "HelloManagedWorld", "()V");
+
+ method_parameters parameters = {env, helper, methodID};
+ execute_function(call_void_java_method, (void*)¶meters);
+}
+jobject instantiate_java_class(JNIEnv* env)
+{
+ jclass class = (*env)->FindClass(env, "JniHelper");
+ jmethodID methodID = (*env)->GetMethodID(env, class, "<init>", "()V");
+
+ jobject object =(*env)->NewObject(env, class, methodID);
+ set_string_member_helper(env, object, "Instantiated from C");
+ return object;
+}
+jstring set_and_write_time_in_seconds(JNIEnv* env, jint seconds)
+{
+ set_time_in_seconds((int)seconds);
+ write_internal_time_in_seconds();
+ return read_internal_string_as_jstring(env);
+}
--- /dev/null
+#pragma once
+
+#include <jni.h>
+
+jint get_jni_version(JNIEnv* env);
+jstring read_constant_jstring(JNIEnv* env);
+jstring write_jstring(JNIEnv* env, jstring string);
+jstring write_jchar_array(JNIEnv* env, jcharArray chars);
+jstring write_string_member(JNIEnv* env, jobject helper);
+void set_string_member(JNIEnv* env, jobject helper);
+void execute_java_function(JNIEnv* env, jobject helper);
+jobject instantiate_java_class(JNIEnv* env);
+jstring set_and_write_time_in_seconds(JNIEnv* env, jint seconds);
--- /dev/null
+#include "native.h"
+#include <stdio.h>
+#include <time.h>
+
+// Pure native functions
+
+#define CHAR_BUFFER_SIZE 256
+static char buffer[CHAR_BUFFER_SIZE];
+
+const char* read_constant_string()
+{
+ return "Hello from C";
+}
+const char* read_internal_string()
+{
+ return buffer;
+}
+void write_internal_string(const char* string)
+{
+ snprintf(buffer, CHAR_BUFFER_SIZE, "%s", string);
+}
+void write_external_string(char* string, size_t maxLength)
+{
+ snprintf(string, maxLength, "Set from C");
+}
+void execute_function(void(*function)(void*), void* context)
+{
+ function(context);
+}
+void set_time_in_seconds(int seconds)
+{
+ time_t timeToSet = seconds;
+ stime(&timeToSet);
+}
+void write_internal_time_in_seconds()
+{
+ time_t systemTime = time(NULL);
+ snprintf(buffer, CHAR_BUFFER_SIZE, "%u", systemTime);
+}
--- /dev/null
+#pragma once
+
+#include <stddef.h>
+
+const char* read_constant_string();
+const char* read_internal_string();
+void write_internal_string(const char* string);
+void write_external_string(char* string, size_t maxLength);
+void execute_function(void(*function)(void*), void* context);
+void set_time_in_seconds(int seconds);
+void write_internal_time_in_seconds();
--- /dev/null
+################################################################################
+#
+# openjdk jni test
+#
+################################################################################
+
+OPENJDK_JNI_TEST_DEPENDENCIES = openjdk
+
+JNI_INCLUDE_PATH = $(BUILD_DIR)/openjdk-$(OPENJDK_VERSION)/build/linux-aarch64-server-release/jdk/include
+
+define OPENJDK_JNI_TEST_BUILD_CMDS
+ # Compile Java classes and generate native headers
+ $(HOST_DIR)/bin/javac -d $(@D) -h $(@D) \
+ $(OPENJDK_JNI_TEST_PKGDIR)/JniTest.java \
+ $(OPENJDK_JNI_TEST_PKGDIR)/JniWrapper.java \
+ $(OPENJDK_JNI_TEST_PKGDIR)/JniHelper.java
+
+ # Compile shared library
+ $(TARGET_MAKE_ENV) $(TARGET_CC) -shared -fPIC \
+ -I$(JNI_INCLUDE_PATH) -I$(JNI_INCLUDE_PATH)/linux -I$(@D) \
+ -o $(@D)/libjni_native.so \
+ $(OPENJDK_JNI_TEST_PKGDIR)/JniWrapper.c \
+ $(OPENJDK_JNI_TEST_PKGDIR)/jni_helper.c \
+ $(OPENJDK_JNI_TEST_PKGDIR)/native.c
+endef
+
+define OPENJDK_JNI_TEST_INSTALL_TARGET_CMDS
+ $(INSTALL) -D -m 755 $(@D)/JniTest.class $(TARGET_DIR)/usr/bin/JniTest.class
+ $(INSTALL) -D -m 755 $(@D)/JniWrapper.class $(TARGET_DIR)/usr/bin/JniWrapper.class
+ $(INSTALL) -D -m 755 $(@D)/JniHelper.class $(TARGET_DIR)/usr/bin/JniHelper.class
+ $(INSTALL) -D -m 755 $(@D)/libjni_native.so $(TARGET_DIR)/usr/lib/libjni_native.so
+endef
+
+$(eval $(generic-package))
BR2_PACKAGE_XORG7=y
BR2_PACKAGE_OPENJDK=y
BR2_PACKAGE_OPENJDK_HELLO_WORLD=y
+ BR2_PACKAGE_OPENJDK_JNI_TEST=y
"""
def login(self):
print(output)
self.assertEqual(exit_code, 0)
self.assertEqual(output, ["Hello, World"])
+
+ cmd = "java -cp /usr/bin JniTest"
+ output, exit_code = self.emulator.run(cmd, 120)
+ print(output)
+ self.assertEqual(exit_code, 0)