diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 8b133a30b..1b37f6bdb 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -215,6 +215,11 @@ int pojavInitOpenGL() { extern void updateMonitorSize(int width, int height); EXTERNAL_API int pojavInit() { + pojav_environ->glfwThreadVmEnv = get_attached_env(pojav_environ->runtimeJavaVMPtr); + if(pojav_environ->glfwThreadVmEnv == NULL) { + printf("Failed to attach Java-side JNIEnv to GLFW thread\n"); + return 0; + } ANativeWindow_acquire(pojav_environ->pojavWindow); pojav_environ->savedWidth = ANativeWindow_getWidth(pojav_environ->pojavWindow); pojav_environ->savedHeight = ANativeWindow_getHeight(pojav_environ->pojavWindow); diff --git a/app_pojavlauncher/src/main/jni/environ/environ.h b/app_pojavlauncher/src/main/jni/environ/environ.h index fbfdb1b09..25dd3d3ab 100644 --- a/app_pojavlauncher/src/main/jni/environ/environ.h +++ b/app_pojavlauncher/src/main/jni/environ/environ.h @@ -51,9 +51,8 @@ struct pojav_environ_s { jbyte* keyDownBuffer; jbyte* mouseDownBuffer; JavaVM* runtimeJavaVMPtr; - JNIEnv* runtimeJNIEnvPtr_JRE; + JNIEnv* glfwThreadVmEnv; JavaVM* dalvikJavaVMPtr; - JNIEnv* dalvikJNIEnvPtr_ANDROID; long showingWindow; bool isInputReady, isCursorEntered, isUseStackQueueCall, shouldUpdateMouse; bool shouldUpdateMonitorSize, monitorSizeConsumed; diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 93c1b9041..5728f2e82 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -30,6 +30,7 @@ #define EVENT_TYPE_MOUSE_BUTTON 1006 #define EVENT_TYPE_SCROLL 1007 +static void installEMUIIteratorMititgation(JNIEnv *vmEnv); static void registerFunctions(JNIEnv *env); jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { @@ -37,28 +38,30 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) { __android_log_print(ANDROID_LOG_INFO, "Native", "Saving DVM environ..."); //Save dalvik global JavaVM pointer pojav_environ->dalvikJavaVMPtr = vm; - (*vm)->GetEnv(vm, (void**) &pojav_environ->dalvikJNIEnvPtr_ANDROID, JNI_VERSION_1_4); - pojav_environ->bridgeClazz = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->NewGlobalRef(pojav_environ->dalvikJNIEnvPtr_ANDROID,(*pojav_environ->dalvikJNIEnvPtr_ANDROID) ->FindClass(pojav_environ->dalvikJNIEnvPtr_ANDROID,"org/lwjgl/glfw/CallbackBridge")); - pojav_environ->method_accessAndroidClipboard = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->GetStaticMethodID(pojav_environ->dalvikJNIEnvPtr_ANDROID, pojav_environ->bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); - pojav_environ->method_onGrabStateChanged = (*pojav_environ->dalvikJNIEnvPtr_ANDROID)->GetStaticMethodID(pojav_environ->dalvikJNIEnvPtr_ANDROID, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V"); + JNIEnv *dvEnv; + (*vm)->GetEnv(vm, (void**) &dvEnv, JNI_VERSION_1_4); + pojav_environ->bridgeClazz = (*dvEnv)->NewGlobalRef(dvEnv,(*dvEnv) ->FindClass(dvEnv,"org/lwjgl/glfw/CallbackBridge")); + pojav_environ->method_accessAndroidClipboard = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "accessAndroidClipboard", "(ILjava/lang/String;)Ljava/lang/String;"); + pojav_environ->method_onGrabStateChanged = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V"); pojav_environ->isUseStackQueueCall = JNI_FALSE; } else if (pojav_environ->dalvikJavaVMPtr != vm) { __android_log_print(ANDROID_LOG_INFO, "Native", "Saving JVM environ..."); pojav_environ->runtimeJavaVMPtr = vm; - (*vm)->GetEnv(vm, (void**) &pojav_environ->runtimeJNIEnvPtr_JRE, JNI_VERSION_1_4); - pojav_environ->vmGlfwClass = (*pojav_environ->runtimeJNIEnvPtr_JRE)->NewGlobalRef(pojav_environ->runtimeJNIEnvPtr_JRE, (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "org/lwjgl/glfw/GLFW")); - pojav_environ->method_glftSetWindowAttrib = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "glfwSetWindowAttrib", "(JII)V"); - pojav_environ->method_internalWindowSizeChanged = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "internalWindowSizeChanged", "(J)V"); - pojav_environ->method_internalChangeMonitorSize = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticMethodID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "internalChangeMonitorSize", "(II)V"); - jfieldID field_keyDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticFieldID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;"); - jobject keyDownBufferJ = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticObjectField(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, field_keyDownBuffer); - pojav_environ->keyDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, keyDownBufferJ); - jfieldID field_mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticFieldID(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, "mouseDownBuffer", "Ljava/nio/ByteBuffer;"); - jobject mouseDownBufferJ = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetStaticObjectField(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, field_mouseDownBuffer); - pojav_environ->mouseDownBuffer = (*pojav_environ->runtimeJNIEnvPtr_JRE)->GetDirectBufferAddress(pojav_environ->runtimeJNIEnvPtr_JRE, mouseDownBufferJ); - hookExec(); - installLwjglDlopenHook(); - installEMUIIteratorMititgation(); + JNIEnv *vmEnv; + (*vm)->GetEnv(vm, (void**) &vmEnv, JNI_VERSION_1_4); + pojav_environ->vmGlfwClass = (*vmEnv)->NewGlobalRef(vmEnv, (*vmEnv)->FindClass(vmEnv, "org/lwjgl/glfw/GLFW")); + pojav_environ->method_glftSetWindowAttrib = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "glfwSetWindowAttrib", "(JII)V"); + pojav_environ->method_internalWindowSizeChanged = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalWindowSizeChanged", "(J)V"); + pojav_environ->method_internalChangeMonitorSize = (*vmEnv)->GetStaticMethodID(vmEnv, pojav_environ->vmGlfwClass, "internalChangeMonitorSize", "(II)V"); + jfieldID field_keyDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "keyDownBuffer", "Ljava/nio/ByteBuffer;"); + jobject keyDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_keyDownBuffer); + pojav_environ->keyDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, keyDownBufferJ); + jfieldID field_mouseDownBuffer = (*vmEnv)->GetStaticFieldID(vmEnv, pojav_environ->vmGlfwClass, "mouseDownBuffer", "Ljava/nio/ByteBuffer;"); + jobject mouseDownBufferJ = (*vmEnv)->GetStaticObjectField(vmEnv, pojav_environ->vmGlfwClass, field_mouseDownBuffer); + pojav_environ->mouseDownBuffer = (*vmEnv)->GetDirectBufferAddress(vmEnv, mouseDownBufferJ); + hookExec(vmEnv); + installLwjglDlopenHook(vmEnv); + installEMUIIteratorMititgation(vmEnv); } if(pojav_environ->dalvikJavaVMPtr == vm) { @@ -90,10 +93,10 @@ ADD_CALLBACK_WWIN(Scroll) #undef ADD_CALLBACK_WWIN void updateMonitorSize(int width, int height) { - (*pojav_environ->runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, pojav_environ->method_internalChangeMonitorSize, width, height); + (*pojav_environ->glfwThreadVmEnv)->CallStaticVoidMethod(pojav_environ->glfwThreadVmEnv, pojav_environ->vmGlfwClass, pojav_environ->method_internalChangeMonitorSize, width, height); } void updateWindowSize(void* window) { - (*pojav_environ->runtimeJNIEnvPtr_JRE)->CallStaticVoidMethod(pojav_environ->runtimeJNIEnvPtr_JRE, pojav_environ->vmGlfwClass, pojav_environ->method_internalWindowSizeChanged, (jlong)window); + (*pojav_environ->glfwThreadVmEnv)->CallStaticVoidMethod(pojav_environ->glfwThreadVmEnv, pojav_environ->vmGlfwClass, pojav_environ->method_internalWindowSizeChanged, (jlong)window); } void pojavPumpEvents(void* window) { @@ -246,10 +249,9 @@ jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env, /** * Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware. */ -void installEMUIIteratorMititgation() { +static void installEMUIIteratorMititgation(JNIEnv *env) { if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return; __android_log_print(ANDROID_LOG_INFO, "EMUIIteratorFix", "Installing..."); - JNIEnv* env = pojav_environ->runtimeJNIEnvPtr_JRE; jclass sharedLibraryUtil = (*env)->FindClass(env, "org/lwjgl/system/SharedLibraryUtil"); if(sharedLibraryUtil == NULL) { __android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to find the target class"); @@ -482,16 +484,7 @@ JNIEXPORT void JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeSetWindowAttrib( // in environ for the Android UI thread but this is the only place that uses it // (very rarely, only in lifecycle callbacks) so i dont care - JavaVM* jvm = pojav_environ->runtimeJavaVMPtr; - JNIEnv *jvm_env = NULL; - jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); - if(env_result == JNI_EDETACHED) { - env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); - } - if(env_result != JNI_OK) { - printf("input_bridge nativeSetWindowAttrib() JNI call failed: %i\n", env_result); - return; - } + JNIEnv *jvm_env = get_attached_env(pojav_environ->runtimeJavaVMPtr); (*jvm_env)->CallStaticVoidMethod( jvm_env, pojav_environ->vmGlfwClass, diff --git a/app_pojavlauncher/src/main/jni/java_exec_hooks.c b/app_pojavlauncher/src/main/jni/java_exec_hooks.c index 4469ba117..830f6e1bc 100644 --- a/app_pojavlauncher/src/main/jni/java_exec_hooks.c +++ b/app_pojavlauncher/src/main/jni/java_exec_hooks.c @@ -72,18 +72,18 @@ static jint hooked_ProcessImpl_forkAndExec(JNIEnv *env, jobject process, jint mo } // Hook the forkAndExec method in the Java runtime for custom executable overriding. -void hookExec() { - jclass cls; +void hookExec(JNIEnv *env) { + jclass hookClass; orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_UNIXProcess_forkAndExec"); if (!orig_ProcessImpl_forkAndExec) { orig_ProcessImpl_forkAndExec = dlsym(RTLD_DEFAULT, "Java_java_lang_ProcessImpl_forkAndExec"); - cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/ProcessImpl"); + hookClass = (*env)->FindClass(env, "java/lang/ProcessImpl"); } else { - cls = (*pojav_environ->runtimeJNIEnvPtr_JRE)->FindClass(pojav_environ->runtimeJNIEnvPtr_JRE, "java/lang/UNIXProcess"); + hookClass = (*env)->FindClass(env, "java/lang/UNIXProcess"); } JNINativeMethod methods[] = { {"forkAndExec", "(I[B[B[BI[BI[B[IZ)I", (void *)&hooked_ProcessImpl_forkAndExec} }; - (*pojav_environ->runtimeJNIEnvPtr_JRE)->RegisterNatives(pojav_environ->runtimeJNIEnvPtr_JRE, cls, methods, 1); + (*env)->RegisterNatives(env, hookClass, methods, 1); printf("Registered forkAndExec\n"); } \ No newline at end of file diff --git a/app_pojavlauncher/src/main/jni/jre_launcher.c b/app_pojavlauncher/src/main/jni/jre_launcher.c index 7ae251f92..6ecfd95d5 100644 --- a/app_pojavlauncher/src/main/jni/jre_launcher.c +++ b/app_pojavlauncher/src/main/jni/jre_launcher.c @@ -185,9 +185,6 @@ JNIEXPORT jint JNICALL Java_com_oracle_dalvik_VMLauncher_launchJVM(JNIEnv *env, jint res = 0; - // Save dalvik JNIEnv pointer for JVM launch thread - pojav_environ->dalvikJNIEnvPtr_ANDROID = env; - if (argsArray == NULL) { LOGE("Args array null, returning"); //handle error diff --git a/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c b/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c index 8694613d1..9990d6f01 100644 --- a/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c +++ b/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c @@ -45,9 +45,8 @@ static jlong ndlopen_bugfix(__attribute__((unused)) JNIEnv *env, /** * Install the LWJGL dlopen hook. This allows us to mitigate linker bugs and add custom library overrides. */ -void installLwjglDlopenHook() { +void installLwjglDlopenHook(JNIEnv *env) { __android_log_print(ANDROID_LOG_INFO, "LwjglLinkerHook", "Installing LWJGL dlopen() hook"); - JNIEnv* env = pojav_environ->runtimeJNIEnvPtr_JRE; jclass dynamicLinkLoader = (*env)->FindClass(env, "org/lwjgl/system/linux/DynamicLinkLoader"); if(dynamicLinkLoader == NULL) { __android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to find the target class"); diff --git a/app_pojavlauncher/src/main/jni/utils.c b/app_pojavlauncher/src/main/jni/utils.c index 571bc7254..e703629c5 100644 --- a/app_pojavlauncher/src/main/jni/utils.c +++ b/app_pojavlauncher/src/main/jni/utils.c @@ -157,6 +157,19 @@ JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_executeBinary(JNI return result; } +JNIEnv* get_attached_env(JavaVM* jvm) { + JNIEnv *jvm_env = NULL; + jint env_result = (*jvm)->GetEnv(jvm, (void**)&jvm_env, JNI_VERSION_1_4); + if(env_result == JNI_EDETACHED) { + env_result = (*jvm)->AttachCurrentThread(jvm, &jvm_env, NULL); + } + if(env_result != JNI_OK) { + printf("get_attached_env failed: %i", env_result); + return NULL; + } + return jvm_env; +} + // METHOD 2 /* JNIEXPORT jint JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_executeForkedBinary(JNIEnv *env, jclass clazz, jobjectArray cmdArgs) { diff --git a/app_pojavlauncher/src/main/jni/utils.h b/app_pojavlauncher/src/main/jni/utils.h index 69583c44e..494dde717 100644 --- a/app_pojavlauncher/src/main/jni/utils.h +++ b/app_pojavlauncher/src/main/jni/utils.h @@ -11,8 +11,8 @@ jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray); jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr); -void hookExec(); -void installLwjglDlopenHook(); -void installEMUIIteratorMititgation(); +void hookExec(JNIEnv *env); +void installLwjglDlopenHook(JNIEnv *env); +JNIEnv* get_attached_env(JavaVM* jvm); JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc);