Fix[pojavexec]: fix incorrect JNIEnv usage in some cases (#6510)

* Fix[pojavexec]: remove central JNIEnv variables

These caused some irreliability, as pojavexec isn't guaranteed to be loaded on the same thread as the call to glfwInit

This fixes:
- 1.3-1.5.2 setting their window size to 0,0 (and thus not working correctly)
- Forge for <1.13 not resizing its window

* Fix[egl_bridge]: remove attachEnvs()

* Whoops[input_bridge]: remove unnecessary prints
This commit is contained in:
Maksim Belov 2025-01-20 12:46:59 +03:00 committed by GitHub
parent c04e3af70d
commit 55e53ea02c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 53 additions and 47 deletions

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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");
}

View File

@ -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

View File

@ -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");

View File

@ -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) {

View File

@ -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);