diff --git a/app_pojavlauncher/src/main/jni/Android.mk b/app_pojavlauncher/src/main/jni/Android.mk index 9ee43d7e75..a820a902a8 100644 --- a/app_pojavlauncher/src/main/jni/Android.mk +++ b/app_pojavlauncher/src/main/jni/Android.mk @@ -46,6 +46,7 @@ LOCAL_SRC_FILES := \ utils.c \ stdio_is.c \ java_exec_hooks.c \ + lwjgl_dlopen_hook.c \ driver_helper/nsbypass.c ifeq ($(TARGET_ARCH_ABI),arm64-v8a) diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 30b89631bb..8b133a30b2 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -258,14 +258,18 @@ EXTERNAL_API void* pojavCreateContext(void* contextSrc) { return br_init_context((basic_render_window_t*)contextSrc); } -EXTERNAL_API JNIEXPORT jlong JNICALL -Java_org_lwjgl_vulkan_VK_getVulkanDriverHandle(ABI_COMPAT JNIEnv *env, ABI_COMPAT jclass thiz) { - printf("EGLBridge: LWJGL-side Vulkan loader requested the Vulkan handle\n"); - // The code below still uses the env var because +void* maybe_load_vulkan() { + // We use the env var because // 1. it's easier to do that // 2. it won't break if something will try to load vulkan and osmesa simultaneously if(getenv("VULKAN_PTR") == NULL) load_vulkan(); - return strtoul(getenv("VULKAN_PTR"), NULL, 0x10); + return (void*) strtoul(getenv("VULKAN_PTR"), NULL, 0x10); +} + +EXTERNAL_API JNIEXPORT jlong JNICALL +Java_org_lwjgl_vulkan_VK_getVulkanDriverHandle(ABI_COMPAT JNIEnv *env, ABI_COMPAT jclass thiz) { + printf("EGLBridge: LWJGL-side Vulkan loader requested the Vulkan handle\n"); + return (jlong) maybe_load_vulkan(); } EXTERNAL_API void pojavSwapInterval(int interval) { diff --git a/app_pojavlauncher/src/main/jni/input_bridge_v3.c b/app_pojavlauncher/src/main/jni/input_bridge_v3.c index 951050a093..e1d406fa8c 100644 --- a/app_pojavlauncher/src/main/jni/input_bridge_v3.c +++ b/app_pojavlauncher/src/main/jni/input_bridge_v3.c @@ -228,47 +228,6 @@ void sendData(int type, int i1, int i2, int i3, int i4) { atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire); } -/** - * Basically a verbatim implementation of ndlopen(), found at - * https://github.com/PojavLauncherTeam/lwjgl3/blob/3.3.1/modules/lwjgl/core/src/generated/c/linux/org_lwjgl_system_linux_DynamicLinkLoader.c#L11 - * The idea is that since, on Android 10 and earlier, the linker doesn't really do namespace nesting. - * It is not a problem as most of the libraries are in the launcher path, but when you try to run - * VulkanMod which loads shaderc outside of the default jni libs directory through this method, - * it can't load it because the path is not in the allowed paths for the anonymous namesapce. - * This method fixes the issue by being in libpojavexec, and thus being in the classloader namespace - */ -jlong ndlopen_bugfix(__attribute__((unused)) JNIEnv *env, - __attribute__((unused)) jclass class, - jlong filename_ptr, - jint jmode) { - const char* filename = (const char*) filename_ptr; - int mode = (int)jmode; - return (jlong) dlopen(filename, mode); -} - -/** - * Install the linker bug mitigation for Android 10 and lower. Fixes VulkanMod crashing on these - * Android versions due to missing namespace nesting. - */ -void installLinkerBugMitigation() { - if(android_get_device_api_level() >= 30) return; - __android_log_print(ANDROID_LOG_INFO, "Api29LinkerFix", "API < 30 detected, installing linker bug mitigation"); - 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, "Api29LinkerFix", "Failed to find the target class"); - (*env)->ExceptionClear(env); - return; - } - JNINativeMethod ndlopenMethod[] = { - {"ndlopen", "(JI)J", &ndlopen_bugfix} - }; - if((*env)->RegisterNatives(env, dynamicLinkLoader, ndlopenMethod, 1) != 0) { - __android_log_print(ANDROID_LOG_ERROR, "Api29LinkerFix", "Failed to register the bugfix method"); - (*env)->ExceptionClear(env); - } -} - /** * This function is meant as a substitute for SharedLibraryUtil.getLibraryPath() that just returns 0 * (thus making the parent Java function return null). This is done to avoid using the LWJGL's default function, diff --git a/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c b/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c new file mode 100644 index 0000000000..96c6333b47 --- /dev/null +++ b/app_pojavlauncher/src/main/jni/lwjgl_dlopen_hook.c @@ -0,0 +1,64 @@ +// +// Created by maks on 06.01.2025. +// + +#include +#include +#include + +#include + +#include +#include +#include + +extern void* maybe_load_vulkan(); + +/** + * Basically a verbatim implementation of ndlopen(), found at + * https://github.com/PojavLauncherTeam/lwjgl3/blob/3.3.1/modules/lwjgl/core/src/generated/c/linux/org_lwjgl_system_linux_DynamicLinkLoader.c#L11 + * but with our own additions for stuff like vulkanmod. + */ +static jlong ndlopen_bugfix(__attribute__((unused)) JNIEnv *env, + __attribute__((unused)) jclass class, + jlong filename_ptr, + jint jmode) { + const char* filename = (const char*) filename_ptr; + + // Oveeride vulkan loading to let us load vulkan ourselves + if(strstr(filename, "libvulkan.so") == filename) { + printf("LWJGL linkerhook: replacing load for libvulkan.so with custom driver\n"); + return (jlong) maybe_load_vulkan(); + } + + // This hook also serves the task of mitigating a bug: the idea is that since, on Android 10 and + // earlier, the linker doesn't really do namespace nesting. + // It is not a problem as most of the libraries are in the launcher path, but when you try to run + // VulkanMod which loads shaderc outside of the default jni libs directory through this method, + // it can't load it because the path is not in the allowed paths for the anonymous namesapce. + // This method fixes the issue by being in libpojavexec, and thus being in the classloader namespace + + int mode = (int)jmode; + return (jlong) dlopen(filename, mode); +} + +/** + * Install the LWJGL dlopen hook. This allows us to mitigate linker bugs and add custom library overrides. + */ +void installLinkerBugMitigation() { + __android_log_print(ANDROID_LOG_INFO, "LwjglLinkerHook", "API < 30 detected, installing linker bug mitigation"); + 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"); + (*env)->ExceptionClear(env); + return; + } + JNINativeMethod ndlopenMethod[] = { + {"ndlopen", "(JI)J", &ndlopen_bugfix} + }; + if((*env)->RegisterNatives(env, dynamicLinkLoader, ndlopenMethod, 1) != 0) { + __android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to register the hooked method"); + (*env)->ExceptionClear(env); + } +} \ No newline at end of file