mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2026-05-24 01:44:38 -04:00
DO NOT USE. Feat[launcher]: start implementing custom JVM launcher
Why do this: 1. This will allow us to fully move argument parsing to Java and skips headroom of parsing the arguments again by the Java's libjli launcher. 2. This removes a lot of implementation quirks of JLI, like the ones related to JVM path resolution. TODO for this to be complete: 1. Transform module-related arguemnts (they need to be in their `=` form for the JVM) 2. Handle `-XX:` style arguments
This commit is contained in:
@@ -3,5 +3,5 @@ package com.oracle.dalvik;
|
||||
public final class VMLauncher {
|
||||
private VMLauncher() {
|
||||
}
|
||||
public static native int launchJVM(String[] args);
|
||||
public static native void launchJVM(String jvmPath, String[] vmArgs, String classpath, String mainClass, String[] applicationArgs);
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouc
|
||||
|
||||
Logger.appendToLog("Info: Java arguments: " + Arrays.toString(javaArgList.toArray(new String[0])));
|
||||
|
||||
JREUtils.launchJavaVM(this, runtime,null,javaArgList, LauncherPreferences.PREF_CUSTOM_JAVA_ARGS);
|
||||
//JREUtils.launchJavaVM(this, runtime,null,javaArgList, LauncherPreferences.PREF_CUSTOM_JAVA_ARGS);
|
||||
} catch (Throwable th) {
|
||||
Tools.showError(this, th, true);
|
||||
}
|
||||
|
||||
@@ -210,16 +210,25 @@ public final class Tools {
|
||||
javaArgList.add("-Dlog4j.configurationFile=" + configFile);
|
||||
}
|
||||
javaArgList.addAll(Arrays.asList(getMinecraftJVMArgs(versionId, gamedir)));
|
||||
javaArgList.add("-cp");
|
||||
javaArgList.add(getLWJGL3ClassPath() + ":" + launchClassPath);
|
||||
//javaArgList.add("-cp");
|
||||
//javaArgList.add(getLWJGL3ClassPath() + ":" + launchClassPath);
|
||||
|
||||
javaArgList.add(versionInfo.mainClass);
|
||||
javaArgList.addAll(Arrays.asList(launchArgs));
|
||||
//javaArgList.add(versionInfo.mainClass);
|
||||
//javaArgList.addAll(Arrays.asList(launchArgs));
|
||||
// ctx.appendlnToLog("full args: "+javaArgList.toString());
|
||||
String args = LauncherPreferences.PREF_CUSTOM_JAVA_ARGS;
|
||||
if(Tools.isValidString(minecraftProfile.javaArgs)) args = minecraftProfile.javaArgs;
|
||||
FFmpegPlugin.discover(activity);
|
||||
JREUtils.launchJavaVM(activity, runtime, gamedir, javaArgList, args);
|
||||
JREUtils.launchJavaVM(
|
||||
activity,
|
||||
runtime,
|
||||
gamedir,
|
||||
javaArgList,
|
||||
getLWJGL3ClassPath() + ":" + launchClassPath,
|
||||
versionInfo.mainClass,
|
||||
launchArgs,
|
||||
args
|
||||
);
|
||||
// If we returned, this means that the JVM exit dialog has been shown and we don't need to be active anymore.
|
||||
// We never return otherwise. The process will be killed anyway, and thus we will become inactive
|
||||
}
|
||||
|
||||
@@ -273,7 +273,14 @@ public class JREUtils {
|
||||
// return ldLibraryPath;
|
||||
}
|
||||
|
||||
public static void launchJavaVM(final AppCompatActivity activity, final Runtime runtime, File gameDirectory, final List<String> JVMArgs, final String userArgsString) throws Throwable {
|
||||
public static void launchJavaVM(final AppCompatActivity activity,
|
||||
final Runtime runtime,
|
||||
File gameDirectory,
|
||||
final List<String> JVMArgs,
|
||||
final String classpath,
|
||||
final String mainClass,
|
||||
final String[] appArgs,
|
||||
final String userArgsString) throws Throwable {
|
||||
String runtimeHome = MultiRTUtils.getRuntimeHome(runtime.name).getAbsolutePath();
|
||||
|
||||
JREUtils.relocateLibPath(runtime, runtimeHome);
|
||||
@@ -306,17 +313,9 @@ public class JREUtils {
|
||||
initJavaRuntime(runtimeHome);
|
||||
setupExitTrap(activity.getApplication());
|
||||
chdir(gameDirectory == null ? Tools.DIR_GAME_NEW : gameDirectory.getAbsolutePath());
|
||||
userArgs.add(0,"java"); //argv[0] is the program name according to C standard.
|
||||
|
||||
final int exitCode = VMLauncher.launchJVM(userArgs.toArray(new String[0]));
|
||||
Logger.appendToLog("Java Exit code: " + exitCode);
|
||||
if (exitCode != 0) {
|
||||
LifecycleAwareAlertDialog.DialogCreator dialogCreator = (dialog, builder)->
|
||||
builder.setMessage(activity.getString(R.string.mcn_exit_title, exitCode))
|
||||
.setPositiveButton(R.string.main_share_logs, (dialogInterface, which)-> shareLog(activity));
|
||||
VMLauncher.launchJVM(jvmLibraryPath+"/libjvm.so", userArgs.toArray(new String[0]), classpath, mainClass.replace('.', '/'), appArgs);
|
||||
|
||||
LifecycleAwareAlertDialog.haltOnDialog(activity.getLifecycle(), activity, dialogCreator);
|
||||
}
|
||||
MainActivity.fullyExit();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#define EVENT_TYPE_SCROLL 1007
|
||||
#define EVENT_TYPE_WINDOW_SIZE 1008
|
||||
|
||||
|
||||
jint (*orig_ProcessImpl_forkAndExec)(JNIEnv *env, jobject process, jint mode, jbyteArray helperpath, jbyteArray prog, jbyteArray argBlock, jint argc, jbyteArray envBlock, jint envc, jbyteArray dir, jintArray std_fds, jboolean redirectErrorStream);
|
||||
|
||||
static void registerFunctions(JNIEnv *env);
|
||||
@@ -344,9 +345,10 @@ JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNI
|
||||
#ifdef DEBUG
|
||||
LOGD("Debug: Clipboard access is going on\n", pojav_environ->isUseStackQueueCall);
|
||||
#endif
|
||||
#define dalvikEnv (scope.env)
|
||||
scope_t scope;
|
||||
scopeAttach(pojav_environ->dalvikJavaVMPtr, &scope);
|
||||
|
||||
JNIEnv *dalvikEnv;
|
||||
(*pojav_environ->dalvikJavaVMPtr)->AttachCurrentThread(pojav_environ->dalvikJavaVMPtr, &dalvikEnv, NULL);
|
||||
assert(dalvikEnv != NULL);
|
||||
assert(pojav_environ->bridgeClazz != NULL);
|
||||
|
||||
@@ -365,8 +367,9 @@ JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNI
|
||||
(*dalvikEnv)->DeleteLocalRef(dalvikEnv, copyDst);
|
||||
(*env)->ReleaseByteArrayElements(env, copySrc, (jbyte *)copySrcC, 0);
|
||||
}
|
||||
(*pojav_environ->dalvikJavaVMPtr)->DetachCurrentThread(pojav_environ->dalvikJavaVMPtr);
|
||||
scopeDetach(pojav_environ->dalvikJavaVMPtr, &scope);
|
||||
return pasteDst;
|
||||
#undef dalvikEnv
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL JavaCritical_org_lwjgl_glfw_CallbackBridge_nativeSetInputReady(jboolean inputReady) {
|
||||
@@ -383,11 +386,13 @@ JNIEXPORT jboolean JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetInputRead
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetGrabbing(__attribute__((unused)) JNIEnv* env, __attribute__((unused)) jclass clazz, jboolean grabbing) {
|
||||
JNIEnv *dalvikEnv;
|
||||
(*pojav_environ->dalvikJavaVMPtr)->AttachCurrentThread(pojav_environ->dalvikJavaVMPtr, &dalvikEnv, NULL);
|
||||
#define dalvikEnv (scope.env)
|
||||
scope_t scope;
|
||||
scopeAttach(pojav_environ->dalvikJavaVMPtr, &scope);
|
||||
(*dalvikEnv)->CallStaticVoidMethod(dalvikEnv, pojav_environ->bridgeClazz, pojav_environ->method_onGrabStateChanged, grabbing);
|
||||
(*pojav_environ->dalvikJavaVMPtr)->DetachCurrentThread(pojav_environ->dalvikJavaVMPtr);
|
||||
scopeDetach(pojav_environ->dalvikJavaVMPtr, &scope);
|
||||
pojav_environ->isGrabbing = grabbing;
|
||||
#undef dalvikEnv
|
||||
}
|
||||
|
||||
jboolean critical_send_char(jchar codepoint) {
|
||||
|
||||
@@ -37,149 +37,232 @@
|
||||
#include "utils.h"
|
||||
#include "environ/environ.h"
|
||||
|
||||
// Uncomment to try redirect signal handling to JVM
|
||||
// #define TRY_SIG2JVM
|
||||
typedef jint (*JNI_CreateJavaVM_t)(JavaVM**, JNIEnv**, void*);
|
||||
|
||||
// PojavLancher: fixme: are these wrong?
|
||||
#define FULL_VERSION "1.8.0-internal"
|
||||
#define DOT_VERSION "1.8"
|
||||
typedef struct {
|
||||
void* handle;
|
||||
JNI_CreateJavaVM_t JNI_CreateJavaVM;
|
||||
} jvm_library_t;
|
||||
|
||||
static const char* const_progname = "java";
|
||||
static const char* const_launcher = "openjdk";
|
||||
static const char** const_jargs = NULL;
|
||||
static const char** const_appclasspath = NULL;
|
||||
static const jboolean const_javaw = JNI_FALSE;
|
||||
static const jboolean const_cpwildcard = JNI_TRUE;
|
||||
static const jint const_ergo_class = 0; // DEFAULT_POLICY
|
||||
static struct sigaction old_sa[NSIG];
|
||||
|
||||
void (*__old_sa)(int signal, siginfo_t *info, void *reserved);
|
||||
int (*JVM_handle_linux_signal)(int signo, siginfo_t* siginfo, void* ucontext, int abort_if_unrecognized);
|
||||
|
||||
void android_sigaction(int signal, siginfo_t *info, void *reserved) {
|
||||
printf("process killed with signal %d code %p addr %p\n", signal,info->si_code,info->si_addr);
|
||||
if (JVM_handle_linux_signal == NULL) { // should not happen, but still
|
||||
__old_sa = old_sa[signal].sa_sigaction;
|
||||
__old_sa(signal,info,reserved);
|
||||
exit(1);
|
||||
} else {
|
||||
// Based on https://github.com/PojavLauncherTeam/openjdk-multiarch-jdk8u/blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/linux/vm/os_linux.cpp#L4688-4693
|
||||
int orig_errno = errno; // Preserve errno value over signal handler.
|
||||
JVM_handle_linux_signal(signal, info, reserved, true);
|
||||
errno = orig_errno;
|
||||
}
|
||||
}
|
||||
typedef jint JNI_CreateJavaVM_func(JavaVM **pvm, void **penv, void *args);
|
||||
|
||||
typedef jint JLI_Launch_func(int argc, char ** argv, /* main argc, argc */
|
||||
int jargc, const char** jargv, /* java args */
|
||||
int appclassc, const char** appclassv, /* app classpath */
|
||||
const char* fullversion, /* full version defined */
|
||||
const char* dotversion, /* dot version defined */
|
||||
const char* pname, /* program name */
|
||||
const char* lname, /* launcher name */
|
||||
jboolean javaargs, /* JAVA_ARGS */
|
||||
jboolean cpwildcard, /* classpath wildcard*/
|
||||
jboolean javaw, /* windows-only javaw */
|
||||
jint ergo /* ergonomics class policy */
|
||||
);
|
||||
|
||||
static jint launchJVM(int margc, char** margv) {
|
||||
void* libjli = dlopen("libjli.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
// Boardwalk: silence
|
||||
// LOGD("JLI lib = %x", (int)libjli);
|
||||
if (NULL == libjli) {
|
||||
LOGE("JLI lib = NULL: %s", dlerror());
|
||||
return -1;
|
||||
}
|
||||
LOGD("Found JLI lib");
|
||||
|
||||
JLI_Launch_func *pJLI_Launch =
|
||||
(JLI_Launch_func *)dlsym(libjli, "JLI_Launch");
|
||||
// Boardwalk: silence
|
||||
// LOGD("JLI_Launch = 0x%x", *(int*)&pJLI_Launch);
|
||||
|
||||
if (NULL == pJLI_Launch) {
|
||||
LOGE("JLI_Launch = NULL");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGD("Calling JLI_Launch");
|
||||
|
||||
return pJLI_Launch(margc, margv,
|
||||
0, NULL, // sizeof(const_jargs) / sizeof(char *), const_jargs,
|
||||
0, NULL, // sizeof(const_appclasspath) / sizeof(char *), const_appclasspath,
|
||||
FULL_VERSION,
|
||||
DOT_VERSION,
|
||||
*margv, // (const_progname != NULL) ? const_progname : *margv,
|
||||
*margv, // (const_launcher != NULL) ? const_launcher : *margv,
|
||||
(const_jargs != NULL) ? JNI_TRUE : JNI_FALSE,
|
||||
const_cpwildcard, const_javaw, const_ergo_class);
|
||||
/*
|
||||
return pJLI_Launch(argc, argv,
|
||||
0, NULL, 0, NULL, FULL_VERSION,
|
||||
DOT_VERSION, *margv, *margv, // "java", "openjdk",
|
||||
JNI_FALSE, JNI_TRUE, JNI_FALSE, 0);
|
||||
*/
|
||||
bool load_vm_library(JNIEnv *env, jstring path, jvm_library_t* library) {
|
||||
void* handle;
|
||||
if(path) {
|
||||
const char* jvm_path = (*env)->GetStringUTFChars(env, path, NULL);
|
||||
if(jvm_path == NULL) {
|
||||
printf("failed to get UTF contents of jvm_path\n");
|
||||
return false;
|
||||
}
|
||||
handle = dlopen(jvm_path, RTLD_NOW);
|
||||
(*env)->ReleaseStringUTFChars(env, path, jvm_path);
|
||||
} else {
|
||||
handle = dlopen("libjvm.so", RTLD_NOW);
|
||||
}
|
||||
if(!handle) {
|
||||
printf("failed to load JVM: %s\n", dlerror());
|
||||
return false;
|
||||
}
|
||||
library->JNI_CreateJavaVM = dlsym(handle, "JNI_CreateJavaVM");
|
||||
if(!library->JNI_CreateJavaVM) {
|
||||
printf("failed to load JVM: %s\n", dlerror());
|
||||
dlclose(handle);
|
||||
return false;
|
||||
}
|
||||
library->handle = handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: com_oracle_dalvik_VMLauncher
|
||||
* Method: launchJVM
|
||||
* Signature: ([Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env, jclass clazz, jobjectArray argsArray) {
|
||||
#ifdef TRY_SIG2JVM
|
||||
void* libjvm = dlopen("libjvm.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||
if (NULL == libjvm) {
|
||||
LOGE("JVM lib = NULL: %s", dlerror());
|
||||
return -1;
|
||||
}
|
||||
JVM_handle_linux_signal = dlsym(libjvm, "JVM_handle_linux_signal");
|
||||
#endif
|
||||
void unload_vm_library(jvm_library_t* library) {
|
||||
dlclose(library->handle);
|
||||
}
|
||||
|
||||
jint res = 0;
|
||||
// int i;
|
||||
//Prepare the signal trapper
|
||||
struct sigaction catcher;
|
||||
memset(&catcher,0,sizeof(sigaction));
|
||||
catcher.sa_sigaction = android_sigaction;
|
||||
catcher.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||
// SA_RESETHAND;
|
||||
#define CATCHSIG(X) sigaction(X, &catcher, &old_sa[X])
|
||||
CATCHSIG(SIGILL);
|
||||
//CATCHSIG(SIGABRT);
|
||||
CATCHSIG(SIGBUS);
|
||||
CATCHSIG(SIGFPE);
|
||||
#ifdef TRY_SIG2JVM
|
||||
CATCHSIG(SIGSEGV);
|
||||
#endif
|
||||
CATCHSIG(SIGSTKFLT);
|
||||
CATCHSIG(SIGPIPE);
|
||||
CATCHSIG(SIGXFSZ);
|
||||
//Signal trapper ready
|
||||
bool transfer_arg(JNIEnv* env, jstring argJString, const char** argStringp) {
|
||||
jsize strlen = (*env)->GetStringUTFLength(env, argJString);
|
||||
char* argString = malloc((strlen + 1) * sizeof(char));
|
||||
if(argString == NULL) return false;
|
||||
(*env)->GetStringUTFRegion(env, argJString, 0, strlen, argString);
|
||||
// Add null terminator just in case if the implementation does not null terminate strings
|
||||
argString[strlen] = 0;
|
||||
*argStringp = argString;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save dalvik JNIEnv pointer for JVM launch thread
|
||||
pojav_environ->dalvikJNIEnvPtr_ANDROID = env;
|
||||
void free_vm_args(JavaVMOption* args, jsize length) {
|
||||
for(jsize i = 0; i < length; i++) {
|
||||
if(args[i].optionString != NULL) free((void*)args[i].optionString);
|
||||
}
|
||||
}
|
||||
|
||||
if (argsArray == NULL) {
|
||||
LOGE("Args array null, returning");
|
||||
//handle error
|
||||
return 0;
|
||||
static void exceptionCheck(JNIEnv *env) {
|
||||
if(!(*env)->ExceptionCheck(env)) return;
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
|
||||
bool initialize_vm_args(JNIEnv* env, jobjectArray vmArgs, jsize length, JavaVMOption* args) {
|
||||
char* failureReason;
|
||||
if(args == NULL) {
|
||||
failureReason = "Out of memory (JavaVMOption* allocation)";
|
||||
goto fail;
|
||||
}
|
||||
if((*env)->PushLocalFrame(env, length) < 0) {
|
||||
exceptionCheck(env);
|
||||
failureReason = "Out of memory (local frame allocation)";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int argc = (*env)->GetArrayLength(env, argsArray);
|
||||
char **argv = convert_to_char_array(env, argsArray);
|
||||
|
||||
LOGD("Done processing args");
|
||||
|
||||
res = launchJVM(argc, argv);
|
||||
|
||||
LOGD("Going to free args");
|
||||
free_char_array(env, argsArray, argv);
|
||||
|
||||
LOGD("Free done");
|
||||
|
||||
return res;
|
||||
for(jsize i = 0; i < length; i++) {
|
||||
jstring argJString = (*env)->GetObjectArrayElement(env, vmArgs, i);
|
||||
if(argJString == NULL) {
|
||||
exceptionCheck(env);
|
||||
failureReason = "One of the argument strings is NULL";
|
||||
goto fail_frame;
|
||||
}
|
||||
if(!transfer_arg(env, argJString, &(args[i].optionString))) {
|
||||
exceptionCheck(env);
|
||||
failureReason = "Argument string transfer failed";
|
||||
goto fail_frame;
|
||||
}
|
||||
}
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
return true;
|
||||
fail_frame:
|
||||
(*env)->PopLocalFrame(env, NULL);
|
||||
fail:
|
||||
free_vm_args(args, length);
|
||||
printf("%s\n",failureReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool transfer_app_args(JNIEnv* host_env, JNIEnv* guest_env, jobjectArray hostArray, jobjectArray guestArray, jsize length) {
|
||||
char* failureReason;
|
||||
if((*host_env)->PushLocalFrame(host_env, length) < 0) {
|
||||
failureReason = "Out of memory (host local frame allocation)";
|
||||
goto fail;
|
||||
}
|
||||
if((*guest_env)->PushLocalFrame(guest_env, length) < 0) {
|
||||
failureReason = "Out of memory (guest local frame allocation)";
|
||||
goto fail1;
|
||||
}
|
||||
for(jsize i = 0; i < length; i++) {
|
||||
jstring hostEntry = (*host_env)->GetObjectArrayElement(host_env, hostArray, i);
|
||||
// All entries are initialized to null by default, so we can just skip null host entries
|
||||
if(hostEntry == NULL) continue;
|
||||
const char* hostEntryUTF = (*host_env)->GetStringUTFChars(host_env, hostEntry, NULL);
|
||||
if(hostEntryUTF == NULL) {
|
||||
failureReason = "Unable to get UTF contents of application argument string";
|
||||
goto fail2;
|
||||
}
|
||||
jstring guestEntry = (*guest_env)->NewStringUTF(guest_env, hostEntryUTF);
|
||||
if(guestEntry == NULL) {
|
||||
failureReason = "Out of memory (guest argument string allocation)";
|
||||
goto fail2;
|
||||
}
|
||||
(*guest_env)->SetObjectArrayElement(guest_env, guestArray, i, guestEntry);
|
||||
}
|
||||
(*guest_env)->PopLocalFrame(guest_env, NULL);
|
||||
(*host_env)->PopLocalFrame(host_env, NULL);
|
||||
return true;
|
||||
fail2:
|
||||
exceptionCheck(guest_env);
|
||||
(*guest_env)->PopLocalFrame(guest_env, NULL);
|
||||
fail1:
|
||||
exceptionCheck(guest_env);
|
||||
(*host_env)->PopLocalFrame(host_env, NULL);
|
||||
fail:
|
||||
exceptionCheck(guest_env);
|
||||
printf("%s\n", failureReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CLASSPATH_ARG "-Djava.class.path="
|
||||
#define CLASSPATH_ARG_LEN 18
|
||||
|
||||
void setup_classpath(JNIEnv* env, jstring jclasspath, jsize length, char* classpath) {
|
||||
memcpy(classpath, CLASSPATH_ARG, CLASSPATH_ARG_LEN);
|
||||
(*env)->GetStringUTFRegion(env, jclasspath, 0, length, &classpath[CLASSPATH_ARG_LEN]);
|
||||
}
|
||||
|
||||
void vmh_exit(int result) {
|
||||
printf("VM_EXIT %i\n", result);
|
||||
}
|
||||
|
||||
#define EXIT(x) { \
|
||||
printf("%s\n", x); \
|
||||
goto exit; \
|
||||
}
|
||||
|
||||
#define EXITVM(x) { \
|
||||
printf("%s\n", x); \
|
||||
exceptionCheck(guest_env); \
|
||||
goto exit_destroyvm; \
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env,
|
||||
__attribute__((unused)) jclass clazz,
|
||||
jstring vmPath,
|
||||
jobjectArray vmArgs,
|
||||
jstring classpath,
|
||||
jstring mainClass,
|
||||
jobjectArray appArgs) {
|
||||
jvm_library_t library;
|
||||
if(!load_vm_library(env, vmPath, &library)) return;
|
||||
|
||||
|
||||
|
||||
jsize inSize = (*env)->GetArrayLength(env, vmArgs);
|
||||
jsize realSize = inSize + 2;
|
||||
JavaVMOption options[realSize];
|
||||
|
||||
jsize classpathLength = (*env)->GetStringUTFLength(env, classpath);
|
||||
size_t totalLength = CLASSPATH_ARG_LEN + classpathLength + 1;
|
||||
char classpath_c[totalLength];
|
||||
setup_classpath(env, classpath, classpathLength, classpath_c);
|
||||
classpath_c[totalLength - 1] = 0; // Null terminate in case if setup_classpath doesn't do it.
|
||||
options[inSize].optionString = classpath_c;
|
||||
|
||||
const char* cmainClass = (*env)->GetStringUTFChars(env, mainClass, NULL);
|
||||
if(cmainClass == NULL) EXIT("Failed to get classname string")
|
||||
|
||||
if(!initialize_vm_args(env, vmArgs, inSize, options)) goto exit;
|
||||
|
||||
options[inSize+1].optionString = "exit";
|
||||
options[inSize+1].extraInfo = vmh_exit;
|
||||
|
||||
JavaVMInitArgs initArgs;
|
||||
initArgs.options = options;
|
||||
initArgs.nOptions = realSize;
|
||||
initArgs.ignoreUnrecognized = JNI_FALSE;
|
||||
initArgs.version = JNI_VERSION_1_6;
|
||||
|
||||
for(jsize i = 0; i < initArgs.nOptions; i++) {
|
||||
printf("%s\n", initArgs.options[i].optionString);
|
||||
}
|
||||
|
||||
JavaVM *guest_jvm;
|
||||
JNIEnv *guest_env;
|
||||
jint res = library.JNI_CreateJavaVM(&guest_jvm, &guest_env, (void*)&initArgs);
|
||||
free_vm_args(options, inSize);
|
||||
if(res < 0) EXIT("Failed to initialize the Java VM")
|
||||
|
||||
jclass guest_main_class = (*guest_env)->FindClass(guest_env, cmainClass);
|
||||
(*env)->ReleaseStringUTFChars(env, mainClass, cmainClass);
|
||||
if(guest_main_class == NULL) EXITVM("Failed to locate main class")
|
||||
|
||||
jmethodID guest_main_method = (*guest_env)->GetStaticMethodID(guest_env, guest_main_class, "main", "([Ljava/lang/String;)V");
|
||||
if(guest_main_method == NULL) EXITVM("Failed to locate main method")
|
||||
|
||||
jclass guest_string_class = (*guest_env)->FindClass(guest_env, "java/lang/String");
|
||||
if(guest_string_class == NULL) EXITVM("Failed to locate String class")
|
||||
|
||||
jsize appArgsCount = (*env)->GetArrayLength(env, appArgs);
|
||||
jobjectArray guestArgsArray = (*guest_env)->NewObjectArray(guest_env, appArgsCount, guest_string_class, NULL);
|
||||
if(!transfer_app_args(env, guest_env, appArgs, guestArgsArray, appArgsCount)) goto exit_destroyvm;
|
||||
|
||||
(*guest_env)->CallStaticVoidMethod(guest_env, guest_main_class, guest_main_method, guestArgsArray);
|
||||
exceptionCheck(guest_env);
|
||||
exit_destroyvm:
|
||||
(*guest_jvm)->DetachCurrentThread(guest_jvm);
|
||||
(*guest_jvm)->DestroyJavaVM(guest_jvm);
|
||||
exit:
|
||||
unload_vm_library(&library);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,19 @@ typedef void (*android_update_LD_LIBRARY_PATH_t)(char*);
|
||||
|
||||
long shared_awt_surface;
|
||||
|
||||
bool scopeAttach(JavaVM* vm, scope_t *scope) {
|
||||
jint err = (*vm)->GetEnv(vm, (void**)&scope->env, JNI_VERSION_1_6);
|
||||
if(err == JNI_EDETACHED) {
|
||||
err = (*vm)->AttachCurrentThread(vm, &scope->env, NULL);
|
||||
if(err == JNI_OK) scope->detach = true;
|
||||
}
|
||||
return err == JNI_OK;
|
||||
}
|
||||
|
||||
void scopeDetach(JavaVM* vm, scope_t *scope) {
|
||||
if(scope->detach) (*vm)->DetachCurrentThread(vm);
|
||||
}
|
||||
|
||||
char** convert_to_char_array(JNIEnv *env, jobjectArray jstringArray) {
|
||||
int num_rows = (*env)->GetArrayLength(env, jstringArray);
|
||||
char **cArray = (char **) malloc(num_rows * sizeof(char*));
|
||||
|
||||
@@ -2,7 +2,13 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
bool detach;
|
||||
JNIEnv *env;
|
||||
} scope_t;
|
||||
|
||||
bool scopeAttach(JavaVM*, scope_t*);
|
||||
void scopeDetach(JavaVM*, scope_t*);
|
||||
|
||||
char** convert_to_char_array(JNIEnv *env, jobjectArray jstringArray);
|
||||
jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows);
|
||||
|
||||
Reference in New Issue
Block a user