mirror of
https://github.com/AngelAuraMC/Amethyst-Android.git
synced 2025-09-11 21:55:34 -04:00
Style[pojavexec]: move hooks to separate dirs, use logging macros
This commit is contained in:
parent
23cc342c95
commit
40e2eb8c21
@ -104,7 +104,8 @@ public class JREUtils {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
if (logcatPb == null) {
|
if (logcatPb == null) {
|
||||||
logcatPb = new ProcessBuilder().command("logcat", /* "-G", "1mb", */ "-v", "brief", "-s", "jrelog:I", "LIBGL:I", "NativeInput").redirectErrorStream(true);
|
// No filtering by tag anymore as that relied on incorrect log levels set in log.h
|
||||||
|
logcatPb = new ProcessBuilder().command("logcat", /* "-G", "1mb", */ "-v", "brief", "-s", "jrelog", "LIBGL", "NativeInput").redirectErrorStream(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("jrelog-logcat","Clearing logcat");
|
Log.i("jrelog-logcat","Clearing logcat");
|
||||||
|
@ -28,12 +28,13 @@ LOCAL_SRC_FILES := \
|
|||||||
ctxbridges/osmesa_loader.c \
|
ctxbridges/osmesa_loader.c \
|
||||||
ctxbridges/swap_interval_no_egl.c \
|
ctxbridges/swap_interval_no_egl.c \
|
||||||
environ/environ.c \
|
environ/environ.c \
|
||||||
|
jvm_hooks/emui_iterator_fix_hook.c \
|
||||||
|
jvm_hooks/java_exec_hooks.c \
|
||||||
|
jvm_hooks/lwjgl_dlopen_hook.c \
|
||||||
input_bridge_v3.c \
|
input_bridge_v3.c \
|
||||||
jre_launcher.c \
|
jre_launcher.c \
|
||||||
utils.c \
|
utils.c \
|
||||||
stdio_is.c \
|
stdio_is.c \
|
||||||
java_exec_hooks.c \
|
|
||||||
lwjgl_dlopen_hook.c \
|
|
||||||
driver_helper/nsbypass.c
|
driver_helper/nsbypass.c
|
||||||
|
|
||||||
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||||
@ -45,7 +46,9 @@ include $(CLEAR_VARS)
|
|||||||
LOCAL_MODULE := exithook
|
LOCAL_MODULE := exithook
|
||||||
LOCAL_LDLIBS := -ldl -llog
|
LOCAL_LDLIBS := -ldl -llog
|
||||||
LOCAL_SHARED_LIBRARIES := bytehook pojavexec
|
LOCAL_SHARED_LIBRARIES := bytehook pojavexec
|
||||||
LOCAL_SRC_FILES := exit_hook.c
|
LOCAL_SRC_FILES := \
|
||||||
|
native_hooks/exit_hook.c \
|
||||||
|
native_hooks/chmod_hook.c
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
#ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
#ifeq ($(TARGET_ARCH_ABI),arm64-v8a)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <EGL/egl.h>
|
#include <EGL/egl.h>
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
#include <android/native_window_jni.h>
|
#include <android/native_window_jni.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -11,11 +10,13 @@
|
|||||||
#include "gl_bridge.h"
|
#include "gl_bridge.h"
|
||||||
#include "egl_loader.h"
|
#include "egl_loader.h"
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
// Created by maks on 17.09.2022.
|
// Created by maks on 17.09.2022.
|
||||||
//
|
//
|
||||||
|
|
||||||
static const char* g_LogTag = "GLBridge";
|
|
||||||
static __thread gl_render_window_t* currentBundle;
|
static __thread gl_render_window_t* currentBundle;
|
||||||
static EGLDisplay g_EglDisplay;
|
static EGLDisplay g_EglDisplay;
|
||||||
|
|
||||||
@ -23,13 +24,11 @@ bool gl_init() {
|
|||||||
if(!dlsym_EGL()) return false;
|
if(!dlsym_EGL()) return false;
|
||||||
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
|
g_EglDisplay = eglGetDisplay_p(EGL_DEFAULT_DISPLAY);
|
||||||
if (g_EglDisplay == EGL_NO_DISPLAY) {
|
if (g_EglDisplay == EGL_NO_DISPLAY) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
|
LOGE("%s", "eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");
|
||||||
"eglGetDisplay_p(EGL_DEFAULT_DISPLAY) returned EGL_NO_DISPLAY");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) {
|
if (eglInitialize_p(g_EglDisplay, 0, 0) != EGL_TRUE) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglInitialize_p() failed: %04x",
|
LOGE("eglInitialize_p() failed: %04x", eglGetError_p());
|
||||||
eglGetError_p());
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -62,14 +61,12 @@ gl_render_window_t* gl_init_context(gl_render_window_t *share) {
|
|||||||
EGLint num_configs = 0;
|
EGLint num_configs = 0;
|
||||||
|
|
||||||
if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) {
|
if (eglChooseConfig_p(g_EglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglChooseConfig_p() failed: %04x",
|
LOGE("eglChooseConfig_p() failed: %04x", eglGetError_p());
|
||||||
eglGetError_p());
|
|
||||||
free(bundle);
|
free(bundle);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (num_configs == 0) {
|
if (num_configs == 0) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "%s",
|
LOGE("%s", "eglChooseConfig_p() found no matching config");
|
||||||
"eglChooseConfig_p() found no matching config");
|
|
||||||
free(bundle);
|
free(bundle);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -96,8 +93,7 @@ gl_render_window_t* gl_init_context(gl_render_window_t *share) {
|
|||||||
bundle->context = eglCreateContext_p(g_EglDisplay, bundle->config, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes);
|
bundle->context = eglCreateContext_p(g_EglDisplay, bundle->config, share == NULL ? EGL_NO_CONTEXT : share->context, egl_context_attributes);
|
||||||
|
|
||||||
if (bundle->context == EGL_NO_CONTEXT) {
|
if (bundle->context == EGL_NO_CONTEXT) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglCreateContext_p() finished with error: %04x",
|
LOGE("eglCreateContext_p() finished with error: %04x", eglGetError_p());
|
||||||
eglGetError_p());
|
|
||||||
free(bundle);
|
free(bundle);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -110,14 +106,14 @@ void gl_swap_surface(gl_render_window_t* bundle) {
|
|||||||
}
|
}
|
||||||
if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);
|
if(bundle->surface != NULL) eglDestroySurface_p(g_EglDisplay, bundle->surface);
|
||||||
if(bundle->newNativeSurface != NULL) {
|
if(bundle->newNativeSurface != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "Switching to new native surface");
|
LOGI("Switching to new native surface");
|
||||||
bundle->nativeSurface = bundle->newNativeSurface;
|
bundle->nativeSurface = bundle->newNativeSurface;
|
||||||
bundle->newNativeSurface = NULL;
|
bundle->newNativeSurface = NULL;
|
||||||
ANativeWindow_acquire(bundle->nativeSurface);
|
ANativeWindow_acquire(bundle->nativeSurface);
|
||||||
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format);
|
ANativeWindow_setBuffersGeometry(bundle->nativeSurface, 0, 0, bundle->format);
|
||||||
bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL);
|
bundle->surface = eglCreateWindowSurface_p(g_EglDisplay, bundle->config, bundle->nativeSurface, NULL);
|
||||||
}else{
|
}else{
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "No new native surface, switching to 1x1 pbuffer");
|
LOGI("No new native surface, switching to 1x1 pbuffer");
|
||||||
bundle->nativeSurface = NULL;
|
bundle->nativeSurface = NULL;
|
||||||
const EGLint pbuffer_attrs[] = {EGL_WIDTH, 1 , EGL_HEIGHT, 1, EGL_NONE};
|
const EGLint pbuffer_attrs[] = {EGL_WIDTH, 1 , EGL_HEIGHT, 1, EGL_NONE};
|
||||||
bundle->surface = eglCreatePbufferSurface_p(g_EglDisplay, bundle->config, pbuffer_attrs);
|
bundle->surface = eglCreatePbufferSurface_p(g_EglDisplay, bundle->config, pbuffer_attrs);
|
||||||
@ -136,11 +132,11 @@ void gl_make_current(gl_render_window_t* bundle) {
|
|||||||
bool hasSetMainWindow = false;
|
bool hasSetMainWindow = false;
|
||||||
if(pojav_environ->mainWindowBundle == NULL) {
|
if(pojav_environ->mainWindowBundle == NULL) {
|
||||||
pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle;
|
pojav_environ->mainWindowBundle = (basic_render_window_t*)bundle;
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle);
|
LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle);
|
||||||
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
||||||
hasSetMainWindow = true;
|
hasSetMainWindow = true;
|
||||||
}
|
}
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface);
|
LOGI("Making current, surface=%p, nativeSurface=%p, newNativeSurface=%p", bundle->surface, bundle->nativeSurface, bundle->newNativeSurface);
|
||||||
if(bundle->surface == NULL) { //it likely will be on the first run
|
if(bundle->surface == NULL) { //it likely will be on the first run
|
||||||
gl_swap_surface(bundle);
|
gl_swap_surface(bundle);
|
||||||
}
|
}
|
||||||
@ -152,7 +148,7 @@ void gl_make_current(gl_render_window_t* bundle) {
|
|||||||
gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle);
|
gl_swap_surface((gl_render_window_t*)pojav_environ->mainWindowBundle);
|
||||||
pojav_environ->mainWindowBundle = NULL;
|
pojav_environ->mainWindowBundle = NULL;
|
||||||
}
|
}
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "eglMakeCurrent returned with error: %04x", eglGetError_p());
|
LOGE("eglMakeCurrent returned with error: %04x", eglGetError_p());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -170,14 +166,14 @@ void gl_swap_buffers() {
|
|||||||
currentBundle->newNativeSurface = NULL;
|
currentBundle->newNativeSurface = NULL;
|
||||||
gl_swap_surface(currentBundle);
|
gl_swap_surface(currentBundle);
|
||||||
eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);
|
eglMakeCurrent_p(g_EglDisplay, currentBundle->surface, currentBundle->surface, currentBundle->context);
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "The window has died, awaiting window change");
|
LOGI("The window has died, awaiting window change");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_setup_window() {
|
void gl_setup_window() {
|
||||||
if(pojav_environ->mainWindowBundle != NULL) {
|
if(pojav_environ->mainWindowBundle != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, changing state");
|
LOGI("Main window bundle is not NULL, changing state");
|
||||||
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
||||||
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
||||||
}
|
}
|
||||||
@ -192,14 +188,14 @@ void gl_swap_interval(int swapInterval) {
|
|||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_lwjgl_opengl_PojavRendererInit_nativeInitGl4esInternals(JNIEnv *env, jclass clazz,
|
Java_org_lwjgl_opengl_PojavRendererInit_nativeInitGl4esInternals(JNIEnv *env, jclass clazz,
|
||||||
jobject function_provider) {
|
jobject function_provider) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "GL4ES internals initializing...");
|
LOGI("GL4ES internals initializing...");
|
||||||
jclass funcProviderClass = (*env)->GetObjectClass(env, function_provider);
|
jclass funcProviderClass = (*env)->GetObjectClass(env, function_provider);
|
||||||
jmethodID method_getFunctionAddress = (*env)->GetMethodID(env, funcProviderClass, "getFunctionAddress", "(Ljava/lang/CharSequence;)J");
|
jmethodID method_getFunctionAddress = (*env)->GetMethodID(env, funcProviderClass, "getFunctionAddress", "(Ljava/lang/CharSequence;)J");
|
||||||
#define GETSYM(N) ((*env)->CallLongMethod(env, function_provider, method_getFunctionAddress, (*env)->NewStringUTF(env, N)));
|
#define GETSYM(N) ((*env)->CallLongMethod(env, function_provider, method_getFunctionAddress, (*env)->NewStringUTF(env, N)));
|
||||||
|
|
||||||
void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height)) = (void*)GETSYM("set_getmainfbsize");
|
void (*set_getmainfbsize)(void (*new_getMainFBSize)(int* width, int* height)) = (void*)GETSYM("set_getmainfbsize");
|
||||||
if(set_getmainfbsize != NULL) {
|
if(set_getmainfbsize != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "GL4ES internals initialized dimension callback");
|
LOGI("GL4ES internals initialized dimension callback");
|
||||||
set_getmainfbsize(gl4esi_get_display_dimensions);
|
set_getmainfbsize(gl4esi_get_display_dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <environ/environ.h>
|
#include <environ/environ.h>
|
||||||
#include <android/log.h>
|
|
||||||
#include "osm_bridge.h"
|
#include "osm_bridge.h"
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
static const char* g_LogTag = "GLBridge";
|
|
||||||
static __thread osm_render_window_t* currentBundle;
|
static __thread osm_render_window_t* currentBundle;
|
||||||
// a tiny buffer for rendering when there's nowhere t render
|
// a tiny buffer for rendering when there's nowhere t render
|
||||||
static char no_render_buffer[4];
|
static char no_render_buffer[4];
|
||||||
@ -49,13 +49,13 @@ void osm_set_no_render_buffer(ANativeWindow_Buffer* buffer) {
|
|||||||
void osm_swap_surfaces(osm_render_window_t* bundle) {
|
void osm_swap_surfaces(osm_render_window_t* bundle) {
|
||||||
if(bundle->nativeSurface != NULL && bundle->newNativeSurface != bundle->nativeSurface) {
|
if(bundle->nativeSurface != NULL && bundle->newNativeSurface != bundle->nativeSurface) {
|
||||||
if(!bundle->disable_rendering) {
|
if(!bundle->disable_rendering) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Unlocking for cleanup...");
|
LOGI("Unlocking for cleanup...");
|
||||||
ANativeWindow_unlockAndPost(bundle->nativeSurface);
|
ANativeWindow_unlockAndPost(bundle->nativeSurface);
|
||||||
}
|
}
|
||||||
ANativeWindow_release(bundle->nativeSurface);
|
ANativeWindow_release(bundle->nativeSurface);
|
||||||
}
|
}
|
||||||
if(bundle->newNativeSurface != NULL) {
|
if(bundle->newNativeSurface != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag, "Switching to new native surface");
|
LOGI("Switching to new native surface");
|
||||||
bundle->nativeSurface = bundle->newNativeSurface;
|
bundle->nativeSurface = bundle->newNativeSurface;
|
||||||
bundle->newNativeSurface = NULL;
|
bundle->newNativeSurface = NULL;
|
||||||
ANativeWindow_acquire(bundle->nativeSurface);
|
ANativeWindow_acquire(bundle->nativeSurface);
|
||||||
@ -63,8 +63,7 @@ void osm_swap_surfaces(osm_render_window_t* bundle) {
|
|||||||
bundle->disable_rendering = false;
|
bundle->disable_rendering = false;
|
||||||
return;
|
return;
|
||||||
}else {
|
}else {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, g_LogTag,
|
LOGI("No new native surface, switching to dummy framebuffer");
|
||||||
"No new native surface, switching to dummy framebuffer");
|
|
||||||
bundle->nativeSurface = NULL;
|
bundle->nativeSurface = NULL;
|
||||||
osm_set_no_render_buffer(&bundle->buffer);
|
osm_set_no_render_buffer(&bundle->buffer);
|
||||||
bundle->disable_rendering = true;
|
bundle->disable_rendering = true;
|
||||||
@ -96,7 +95,7 @@ void osm_make_current(osm_render_window_t* bundle) {
|
|||||||
currentBundle = bundle;
|
currentBundle = bundle;
|
||||||
if(pojav_environ->mainWindowBundle == NULL) {
|
if(pojav_environ->mainWindowBundle == NULL) {
|
||||||
pojav_environ->mainWindowBundle = (basic_render_window_t*) bundle;
|
pojav_environ->mainWindowBundle = (basic_render_window_t*) bundle;
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is now %p", pojav_environ->mainWindowBundle);
|
LOGI("Main window bundle is now %p", pojav_environ->mainWindowBundle);
|
||||||
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
||||||
hasSetMainWindow = true;
|
hasSetMainWindow = true;
|
||||||
}
|
}
|
||||||
@ -130,7 +129,7 @@ void osm_swap_buffers() {
|
|||||||
|
|
||||||
void osm_setup_window() {
|
void osm_setup_window() {
|
||||||
if(pojav_environ->mainWindowBundle != NULL) {
|
if(pojav_environ->mainWindowBundle != NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, g_LogTag, "Main window bundle is not NULL, changing state");
|
LOGI("Main window bundle is not NULL, changing state");
|
||||||
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
pojav_environ->mainWindowBundle->state = STATE_RENDERER_NEW_WINDOW;
|
||||||
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
pojav_environ->mainWindowBundle->newNativeSurface = pojav_environ->pojavWindow;
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,11 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/native_window.h>
|
#include <android/native_window.h>
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
// Taken from https://android.googlesource.com/platform/frameworks/native/+/41abd67/include/ui/egl/android_natives.h
|
// Taken from https://android.googlesource.com/platform/frameworks/native/+/41abd67/include/ui/egl/android_natives.h
|
||||||
// Might be outdated, if you can find a more recent version please add it there
|
// Might be outdated, if you can find a more recent version please add it there
|
||||||
// region android_native_base_t definition
|
// region android_native_base_t definition
|
||||||
@ -227,17 +229,17 @@ void setNativeWindowSwapInterval(struct ANativeWindow* nativeWindow, int swapInt
|
|||||||
}
|
}
|
||||||
struct ANativeWindow_real* nativeWindowReal = (struct ANativeWindow_real*) nativeWindow;
|
struct ANativeWindow_real* nativeWindowReal = (struct ANativeWindow_real*) nativeWindow;
|
||||||
if(nativeWindowReal->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
|
if(nativeWindowReal->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "ANativeWindow magic does not match. Expected %i, got %i",
|
LOGW("ANativeWindow magic does not match. Expected %i, got %i",
|
||||||
ANDROID_NATIVE_WINDOW_MAGIC, nativeWindowReal->common.magic);
|
ANDROID_NATIVE_WINDOW_MAGIC, nativeWindowReal->common.magic);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(nativeWindowReal->common.version != sizeof(struct ANativeWindow_real)) {
|
if(nativeWindowReal->common.version != sizeof(struct ANativeWindow_real)) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "ANativeWindow version does not match. Expected %i, got %i",
|
LOGW("ANativeWindow version does not match. Expected %i, got %i",
|
||||||
sizeof(struct ANativeWindow_real), nativeWindowReal->common.version);
|
sizeof(struct ANativeWindow_real), nativeWindowReal->common.version);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int error;
|
int error;
|
||||||
if((error = nativeWindowReal->setSwapInterval(nativeWindow, swapInterval)) != 0) {
|
if((error = nativeWindowReal->setSwapInterval(nativeWindow, swapInterval)) != 0) {
|
||||||
__android_log_print(ANDROID_LOG_WARN, "SwapIntervalNoEGL", "Failed to set swap interval: %s", strerror(-error));
|
LOGW("Failed to set swap interval: %s", strerror(-error));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -82,7 +82,6 @@ bool linker_ns_load(const char* lib_search_path) {
|
|||||||
// load the two functions we need
|
// load the two functions we need
|
||||||
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
|
android_create_namespace = dlsym(ld_android_handle, "__loader_android_create_namespace");
|
||||||
ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces");
|
ld_android_link_namespaces_t android_link_namespaces = dlsym(ld_android_handle, "__loader_android_link_namespaces");
|
||||||
__android_log_print(ANDROID_LOG_INFO, "nsbypass", "found functions at %p %p", android_create_namespace, android_link_namespaces);
|
|
||||||
if(android_create_namespace == NULL || android_link_namespaces == NULL) {
|
if(android_create_namespace == NULL || android_link_namespaces == NULL) {
|
||||||
dlclose(ld_android_handle);
|
dlclose(ld_android_handle);
|
||||||
return false;
|
return false;
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "environ.h"
|
#include "environ.h"
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
struct pojav_environ_s *pojav_environ;
|
struct pojav_environ_s *pojav_environ;
|
||||||
__attribute__((constructor)) void env_init() {
|
__attribute__((constructor)) void env_init() {
|
||||||
char* strptr_env = getenv("POJAV_ENVIRON");
|
char* strptr_env = getenv("POJAV_ENVIRON");
|
||||||
if(strptr_env == NULL) {
|
if(strptr_env == NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Environ", "No environ found, creating...");
|
LOGI("No environ found, creating...");
|
||||||
pojav_environ = malloc(sizeof(struct pojav_environ_s));
|
pojav_environ = malloc(sizeof(struct pojav_environ_s));
|
||||||
assert(pojav_environ);
|
assert(pojav_environ);
|
||||||
memset(pojav_environ, 0 , sizeof(struct pojav_environ_s));
|
memset(pojav_environ, 0 , sizeof(struct pojav_environ_s));
|
||||||
@ -19,8 +22,8 @@ __attribute__((constructor)) void env_init() {
|
|||||||
setenv("POJAV_ENVIRON", strptr_env, 1);
|
setenv("POJAV_ENVIRON", strptr_env, 1);
|
||||||
free(strptr_env);
|
free(strptr_env);
|
||||||
}else{
|
}else{
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Environ", "Found existing environ: %s", strptr_env);
|
LOGI("Found existing environ: %s", strptr_env);
|
||||||
pojav_environ = (void*) strtoul(strptr_env, NULL, 0x10);
|
pojav_environ = (void*) strtoul(strptr_env, NULL, 0x10);
|
||||||
}
|
}
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Environ", "%p", pojav_environ);
|
LOGI("%p", pojav_environ);
|
||||||
}
|
}
|
@ -1,115 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by maks on 15.01.2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <bytehook.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <android/log.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include "stdio_is.h"
|
|
||||||
|
|
||||||
static _Atomic bool exit_tripped = false;
|
|
||||||
|
|
||||||
typedef void (*exit_func)(int);
|
|
||||||
|
|
||||||
static void custom_exit(int code) {
|
|
||||||
// If the exit was already done (meaning it is recursive or from a different thread), pass the call through
|
|
||||||
if(exit_tripped) {
|
|
||||||
BYTEHOOK_CALL_PREV(custom_exit, exit_func, code);
|
|
||||||
BYTEHOOK_POP_STACK();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
exit_tripped = true;
|
|
||||||
// Perform a nominal exit, as we expect.
|
|
||||||
nominal_exit(code, false);
|
|
||||||
BYTEHOOK_POP_STACK();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hooks for chmod and fchmod that always return success.
|
|
||||||
// This allows older Android versions to work with Java NIO zipfs inside of the Pojav folder.
|
|
||||||
typedef int (*chmod_func)(const char*, mode_t);
|
|
||||||
typedef int (*fchmod_func)(int, mode_t);
|
|
||||||
|
|
||||||
#define TEMPLATE_HOOK(X, Y, Z, W) static int X(Y, mode_t mode) { \
|
|
||||||
int result = BYTEHOOK_CALL_PREV(X, Z, W, mode); \
|
|
||||||
if(result != 0) errno = 0; \
|
|
||||||
BYTEHOOK_POP_STACK(); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
|
|
||||||
TEMPLATE_HOOK(custom_chmod, const char* filename, chmod_func, filename)
|
|
||||||
TEMPLATE_HOOK(custom_fchmod, int fd, fchmod_func, fd)
|
|
||||||
|
|
||||||
#undef TEMPLATE_HOOK
|
|
||||||
|
|
||||||
static void custom_atexit() {
|
|
||||||
// Same as custom_exit, but without the code or the exit passthrough.
|
|
||||||
if(exit_tripped) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
exit_tripped = true;
|
|
||||||
nominal_exit(0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef bytehook_stub_t (*bytehook_hook_all_t)(const char *callee_path_name, const char *sym_name, void *new_func,
|
|
||||||
bytehook_hooked_t hooked, void *hooked_arg);
|
|
||||||
|
|
||||||
static void create_chmod_hooks(bytehook_hook_all_t bytehook_hook_all_p) {
|
|
||||||
bytehook_stub_t stub_chmod = bytehook_hook_all_p(NULL, "chmod", &custom_chmod, NULL, NULL);
|
|
||||||
bytehook_stub_t stub_fchmod = bytehook_hook_all_p(NULL, "fchmod", &custom_fchmod, NULL, NULL);
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "chmod_hook", "Successfully initialized chmod hooks, stubs: %p %p", stub_chmod, stub_fchmod);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void create_hooks(bytehook_hook_all_t bytehook_hook_all_p) {
|
|
||||||
bytehook_stub_t stub_exit = bytehook_hook_all_p(NULL, "exit", &custom_exit, NULL, NULL);
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "exit_hook", "Successfully initialized exit hook, stub: %p", stub_exit);
|
|
||||||
// TODO: figure out proper android version where these should apply
|
|
||||||
create_chmod_hooks(bytehook_hook_all_p);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool init_hooks() {
|
|
||||||
void* bytehook_handle = dlopen("libbytehook.so", RTLD_NOW);
|
|
||||||
if(bytehook_handle == NULL) {
|
|
||||||
goto dlerror;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytehook_hook_all_t bytehook_hook_all_p;
|
|
||||||
int (*bytehook_init_p)(int mode, bool debug);
|
|
||||||
|
|
||||||
bytehook_hook_all_p = dlsym(bytehook_handle, "bytehook_hook_all");
|
|
||||||
bytehook_init_p = dlsym(bytehook_handle, "bytehook_init");
|
|
||||||
|
|
||||||
if(bytehook_hook_all_p == NULL || bytehook_init_p == NULL) {
|
|
||||||
goto dlerror;
|
|
||||||
}
|
|
||||||
int bhook_status = bytehook_init_p(BYTEHOOK_MODE_AUTOMATIC, false);
|
|
||||||
if(bhook_status == BYTEHOOK_STATUS_CODE_OK) {
|
|
||||||
create_hooks(bytehook_hook_all_p);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "exit_hook", "bytehook_init failed (%i)", bhook_status);
|
|
||||||
dlclose(bytehook_handle);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dlerror:
|
|
||||||
if(bytehook_handle != NULL) dlclose(bytehook_handle);
|
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "exit_hook", "Failed to load hook library: %s", dlerror());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
|
||||||
Java_net_kdt_pojavlaunch_utils_JREUtils_initializeHooks(JNIEnv *env, jclass clazz) {
|
|
||||||
bool hooks_ready = init_hooks();
|
|
||||||
if(!hooks_ready){
|
|
||||||
// If we can't hook, register atexit(). This won't report a proper error code,
|
|
||||||
// but it will prevent a SIGSEGV or a SIGABRT from the depths of Dalvik that happens
|
|
||||||
// on exit().
|
|
||||||
atexit(custom_atexit);
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,9 +19,11 @@
|
|||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "environ/environ.h"
|
#include "environ/environ.h"
|
||||||
|
#include "jvm_hooks/jvm_hooks.h"
|
||||||
|
|
||||||
#define EVENT_TYPE_CHAR 1000
|
#define EVENT_TYPE_CHAR 1000
|
||||||
#define EVENT_TYPE_CHAR_MODS 1001
|
#define EVENT_TYPE_CHAR_MODS 1001
|
||||||
@ -30,12 +32,11 @@
|
|||||||
#define EVENT_TYPE_MOUSE_BUTTON 1006
|
#define EVENT_TYPE_MOUSE_BUTTON 1006
|
||||||
#define EVENT_TYPE_SCROLL 1007
|
#define EVENT_TYPE_SCROLL 1007
|
||||||
|
|
||||||
static void installEMUIIteratorMititgation(JNIEnv *vmEnv);
|
|
||||||
static void registerFunctions(JNIEnv *env);
|
static void registerFunctions(JNIEnv *env);
|
||||||
|
|
||||||
jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
|
jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
|
||||||
if (pojav_environ->dalvikJavaVMPtr == NULL) {
|
if (pojav_environ->dalvikJavaVMPtr == NULL) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Native", "Saving DVM environ...");
|
LOGI("Saving DVM environ...");
|
||||||
//Save dalvik global JavaVM pointer
|
//Save dalvik global JavaVM pointer
|
||||||
pojav_environ->dalvikJavaVMPtr = vm;
|
pojav_environ->dalvikJavaVMPtr = vm;
|
||||||
JNIEnv *dvEnv;
|
JNIEnv *dvEnv;
|
||||||
@ -45,7 +46,7 @@ jint JNI_OnLoad(JavaVM* vm, __attribute__((unused)) void* reserved) {
|
|||||||
pojav_environ->method_onGrabStateChanged = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V");
|
pojav_environ->method_onGrabStateChanged = (*dvEnv)->GetStaticMethodID(dvEnv, pojav_environ->bridgeClazz, "onGrabStateChanged", "(Z)V");
|
||||||
pojav_environ->isUseStackQueueCall = JNI_FALSE;
|
pojav_environ->isUseStackQueueCall = JNI_FALSE;
|
||||||
} else if (pojav_environ->dalvikJavaVMPtr != vm) {
|
} else if (pojav_environ->dalvikJavaVMPtr != vm) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "Native", "Saving JVM environ...");
|
LOGI("Saving JVM environ...");
|
||||||
pojav_environ->runtimeJavaVMPtr = vm;
|
pojav_environ->runtimeJavaVMPtr = vm;
|
||||||
JNIEnv *vmEnv;
|
JNIEnv *vmEnv;
|
||||||
(*vm)->GetEnv(vm, (void**) &vmEnv, JNI_VERSION_1_4);
|
(*vm)->GetEnv(vm, (void**) &vmEnv, JNI_VERSION_1_4);
|
||||||
@ -231,42 +232,6 @@ void sendData(int type, int i1, int i2, int i3, int i4) {
|
|||||||
atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire);
|
atomic_fetch_add_explicit(&pojav_environ->eventCounter, 1, memory_order_acquire);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
|
||||||
* which will hang the crappy EMUI linker by dlopen()ing inside of dl_iterate_phdr().
|
|
||||||
* @return 0, to make the parent Java function return null immediately.
|
|
||||||
* For reference: https://github.com/PojavLauncherTeam/lwjgl3/blob/fix_huawei_hang/modules/lwjgl/core/src/main/java/org/lwjgl/system/SharedLibraryUtil.java
|
|
||||||
*/
|
|
||||||
jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env,
|
|
||||||
__attribute__((unused)) jclass class,
|
|
||||||
__attribute__((unused)) jlong pLibAddress,
|
|
||||||
__attribute__((unused)) jlong sOutAddress,
|
|
||||||
__attribute__((unused)) jint bufSize){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware.
|
|
||||||
*/
|
|
||||||
static void installEMUIIteratorMititgation(JNIEnv *env) {
|
|
||||||
if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return;
|
|
||||||
__android_log_print(ANDROID_LOG_INFO, "EMUIIteratorFix", "Installing...");
|
|
||||||
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");
|
|
||||||
(*env)->ExceptionClear(env);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
JNINativeMethod getLibraryPathMethod[] = {
|
|
||||||
{"getLibraryPath", "(JJI)I", &getLibraryPath_fix}
|
|
||||||
};
|
|
||||||
if((*env)->RegisterNatives(env, sharedLibraryUtil, getLibraryPathMethod, 1) != 0) {
|
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "EMUIIteratorFix", "Failed to register the mitigation method");
|
|
||||||
(*env)->ExceptionClear(env);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void critical_set_stackqueue(jboolean use_input_stack_queue) {
|
void critical_set_stackqueue(jboolean use_input_stack_queue) {
|
||||||
pojav_environ->isUseStackQueueCall = (int) use_input_stack_queue;
|
pojav_environ->isUseStackQueueCall = (int) use_input_stack_queue;
|
||||||
}
|
}
|
||||||
@ -308,7 +273,7 @@ JNIEXPORT jboolean JNICALL JavaCritical_org_lwjgl_glfw_CallbackBridge_nativeSetI
|
|||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
LOGD("Debug: Changing input state, isReady=%d, pojav_environ->isUseStackQueueCall=%d\n", inputReady, pojav_environ->isUseStackQueueCall);
|
LOGD("Debug: Changing input state, isReady=%d, pojav_environ->isUseStackQueueCall=%d\n", inputReady, pojav_environ->isUseStackQueueCall);
|
||||||
#endif
|
#endif
|
||||||
__android_log_print(ANDROID_LOG_INFO, "NativeInput", "Input ready: %i", inputReady);
|
LOGI("Input ready: %i", inputReady);
|
||||||
pojav_environ->isInputReady = inputReady;
|
pojav_environ->isInputReady = inputReady;
|
||||||
return pojav_environ->isUseStackQueueCall;
|
return pojav_environ->isUseStackQueueCall;
|
||||||
}
|
}
|
||||||
@ -550,9 +515,9 @@ static void registerFunctions(JNIEnv *env) {
|
|||||||
bool use_critical_cc = tryCriticalNative(env);
|
bool use_critical_cc = tryCriticalNative(env);
|
||||||
jclass bridge_class = (*env)->FindClass(env, "org/lwjgl/glfw/CallbackBridge");
|
jclass bridge_class = (*env)->FindClass(env, "org/lwjgl/glfw/CallbackBridge");
|
||||||
if(use_critical_cc) {
|
if(use_critical_cc) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is available. Enjoy the 4.6x times faster input!");
|
LOGI("CriticalNative is available. Enjoy the 4.6x times faster input!");
|
||||||
}else{
|
}else{
|
||||||
__android_log_print(ANDROID_LOG_INFO, "pojavexec", "CriticalNative is not available. Upgrade, maybe?");
|
LOGI("CriticalNative is not available. Upgrade, maybe?");
|
||||||
}
|
}
|
||||||
(*env)->RegisterNatives(env,
|
(*env)->RegisterNatives(env,
|
||||||
bridge_class,
|
bridge_class,
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 23.01.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "jvm_hooks.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
* which will hang the crappy EMUI linker by dlopen()ing inside of dl_iterate_phdr().
|
||||||
|
* @return 0, to make the parent Java function return null immediately.
|
||||||
|
* For reference: https://github.com/PojavLauncherTeam/lwjgl3/blob/fix_huawei_hang/modules/lwjgl/core/src/main/java/org/lwjgl/system/SharedLibraryUtil.java
|
||||||
|
*/
|
||||||
|
jint getLibraryPath_fix(__attribute__((unused)) JNIEnv *env,
|
||||||
|
__attribute__((unused)) jclass class,
|
||||||
|
__attribute__((unused)) jlong pLibAddress,
|
||||||
|
__attribute__((unused)) jlong sOutAddress,
|
||||||
|
__attribute__((unused)) jint bufSize){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install the linker hang mitigation that is meant to prevent linker hangs on old EMUI firmware.
|
||||||
|
*/
|
||||||
|
void installEMUIIteratorMititgation(JNIEnv *env) {
|
||||||
|
if(getenv("POJAV_EMUI_ITERATOR_MITIGATE") == NULL) return;
|
||||||
|
LOGI("Installing...");
|
||||||
|
jclass sharedLibraryUtil = (*env)->FindClass(env, "org/lwjgl/system/SharedLibraryUtil");
|
||||||
|
if(sharedLibraryUtil == NULL) {
|
||||||
|
LOGE("Failed to find target class");
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JNINativeMethod getLibraryPathMethod[] = {
|
||||||
|
{"getLibraryPath", "(JJI)I", &getLibraryPath_fix}
|
||||||
|
};
|
||||||
|
if((*env)->RegisterNatives(env, sharedLibraryUtil, getLibraryPathMethod, 1) != 0) {
|
||||||
|
LOGE("Failed to register the mitigation method");
|
||||||
|
(*env)->ExceptionClear(env);
|
||||||
|
}
|
||||||
|
}
|
@ -2,15 +2,14 @@
|
|||||||
// Created by maks on 05.01.2025.
|
// Created by maks on 05.01.2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <jni.h>
|
#include "jvm_hooks.h"
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
#include <environ/environ.h>
|
#include "environ/environ.h"
|
||||||
#include <android/log.h>
|
#include "utils.h"
|
||||||
#include <utils.h>
|
|
||||||
|
|
||||||
static 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 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);
|
||||||
|
|
14
app_pojavlauncher/src/main/jni/jvm_hooks/jvm_hooks.h
Normal file
14
app_pojavlauncher/src/main/jni/jvm_hooks/jvm_hooks.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 23.01.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef POJAVLAUNCHER_JVM_HOOKS_H
|
||||||
|
#define POJAVLAUNCHER_JVM_HOOKS_H
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
void installEMUIIteratorMititgation(JNIEnv *env);
|
||||||
|
void installLwjglDlopenHook(JNIEnv *env);
|
||||||
|
void hookExec(JNIEnv *env);
|
||||||
|
|
||||||
|
#endif //POJAVLAUNCHER_JVM_HOOKS_H
|
@ -2,16 +2,19 @@
|
|||||||
// Created by maks on 06.01.2025.
|
// Created by maks on 06.01.2025.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <android/api-level.h>
|
#include "jvm_hooks.h"
|
||||||
#include <android/log.h>
|
|
||||||
#include <jni.h>
|
|
||||||
|
|
||||||
#include <environ/environ.h>
|
#include <android/api-level.h>
|
||||||
|
|
||||||
|
#include "environ/environ.h"
|
||||||
|
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
extern void* maybe_load_vulkan();
|
extern void* maybe_load_vulkan();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,10 +49,10 @@ 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.
|
* Install the LWJGL dlopen hook. This allows us to mitigate linker bugs and add custom library overrides.
|
||||||
*/
|
*/
|
||||||
void installLwjglDlopenHook(JNIEnv *env) {
|
void installLwjglDlopenHook(JNIEnv *env) {
|
||||||
__android_log_print(ANDROID_LOG_INFO, "LwjglLinkerHook", "Installing LWJGL dlopen() hook");
|
LOGI("Installing LWJGL dlopen() hook");
|
||||||
jclass dynamicLinkLoader = (*env)->FindClass(env, "org/lwjgl/system/linux/DynamicLinkLoader");
|
jclass dynamicLinkLoader = (*env)->FindClass(env, "org/lwjgl/system/linux/DynamicLinkLoader");
|
||||||
if(dynamicLinkLoader == NULL) {
|
if(dynamicLinkLoader == NULL) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to find the target class");
|
LOGE("Failed to find the target class");
|
||||||
(*env)->ExceptionClear(env);
|
(*env)->ExceptionClear(env);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -57,7 +60,7 @@ void installLwjglDlopenHook(JNIEnv *env) {
|
|||||||
{"ndlopen", "(JI)J", &ndlopen_bugfix}
|
{"ndlopen", "(JI)J", &ndlopen_bugfix}
|
||||||
};
|
};
|
||||||
if((*env)->RegisterNatives(env, dynamicLinkLoader, ndlopenMethod, 1) != 0) {
|
if((*env)->RegisterNatives(env, dynamicLinkLoader, ndlopenMethod, 1) != 0) {
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "LwjglLinkerHook", "Failed to register the hooked method");
|
LOGE("Failed to register the hooked method");
|
||||||
(*env)->ExceptionClear(env);
|
(*env)->ExceptionClear(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
#ifdef __ANDROID__
|
#ifndef POJAVLAUNCHER_LOG_H
|
||||||
|
#define POJAVLAUNCHER_LOG_H
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#ifndef TAG
|
||||||
#define TAG "jrelog"
|
#define TAG "jrelog"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -8,12 +11,14 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOGE(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
|
||||||
#define LOGW(...) __android_log_print(ANDROID_LOG_SILENT, TAG, __VA_ARGS__)
|
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
|
||||||
#define LOGI(...) __android_log_print(ANDROID_LOG_SILENT, TAG, __VA_ARGS__)
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
33
app_pojavlauncher/src/main/jni/native_hooks/chmod_hook.c
Normal file
33
app_pojavlauncher/src/main/jni/native_hooks/chmod_hook.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 23.01.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "native_hooks.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
// Hooks for chmod and fchmod that always return success.
|
||||||
|
// This allows older Android versions to work with Java NIO zipfs inside of the Pojav folder.
|
||||||
|
typedef int (*chmod_func)(const char*, mode_t);
|
||||||
|
typedef int (*fchmod_func)(int, mode_t);
|
||||||
|
|
||||||
|
#define TEMPLATE_HOOK(X, Y, Z, W) static int X(Y, mode_t mode) { \
|
||||||
|
int result = BYTEHOOK_CALL_PREV(X, Z, W, mode); \
|
||||||
|
if(result != 0) errno = 0; \
|
||||||
|
BYTEHOOK_POP_STACK(); \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
|
||||||
|
TEMPLATE_HOOK(custom_chmod, const char* filename, chmod_func, filename)
|
||||||
|
TEMPLATE_HOOK(custom_fchmod, int fd, fchmod_func, fd)
|
||||||
|
|
||||||
|
#undef TEMPLATE_HOOK
|
||||||
|
|
||||||
|
void create_chmod_hooks(bytehook_hook_all_t bytehook_hook_all_p) {
|
||||||
|
bytehook_stub_t stub_chmod = bytehook_hook_all_p(NULL, "chmod", &custom_chmod, NULL, NULL);
|
||||||
|
bytehook_stub_t stub_fchmod = bytehook_hook_all_p(NULL, "fchmod", &custom_fchmod, NULL, NULL);
|
||||||
|
LOGI("Successfully initialized chmod hooks, stubs: %p %p", stub_chmod, stub_fchmod);
|
||||||
|
}
|
86
app_pojavlauncher/src/main/jni/native_hooks/exit_hook.c
Normal file
86
app_pojavlauncher/src/main/jni/native_hooks/exit_hook.c
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 15.01.2025.
|
||||||
|
//
|
||||||
|
#include "native_hooks.h"
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <bytehook.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "stdio_is.h"
|
||||||
|
|
||||||
|
#define TAG __FILE_NAME__
|
||||||
|
#include <log.h>
|
||||||
|
|
||||||
|
static _Atomic bool exit_tripped = false;
|
||||||
|
|
||||||
|
static int exit_code = 0;
|
||||||
|
|
||||||
|
typedef void (*exit_func)(int);
|
||||||
|
// Use the exit hook *only* to store the exit code.
|
||||||
|
static void custom_exit(int code) {
|
||||||
|
exit_code = code;
|
||||||
|
BYTEHOOK_CALL_PREV(custom_exit, exit_func, code);
|
||||||
|
BYTEHOOK_POP_STACK();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void custom_atexit() {
|
||||||
|
if(exit_tripped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exit_tripped = true;
|
||||||
|
nominal_exit(exit_code, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_hooks(bytehook_hook_all_t bytehook_hook_all_p) {
|
||||||
|
bytehook_stub_t stub_exit = bytehook_hook_all_p(NULL, "exit", &custom_exit, NULL, NULL);
|
||||||
|
LOGI("Successfully initialized exit hook, stub: %p", stub_exit);
|
||||||
|
// Only apply chmod hooks on devices where the game directory is in games/PojavLauncher
|
||||||
|
// which is below API 29
|
||||||
|
if(android_get_device_api_level() < 29) {
|
||||||
|
create_chmod_hooks(bytehook_hook_all_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool init_hooks() {
|
||||||
|
void* bytehook_handle = dlopen("libbytehook.so", RTLD_NOW);
|
||||||
|
if(bytehook_handle == NULL) {
|
||||||
|
goto dlerror;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytehook_hook_all_t bytehook_hook_all_p;
|
||||||
|
int (*bytehook_init_p)(int mode, bool debug);
|
||||||
|
|
||||||
|
bytehook_hook_all_p = dlsym(bytehook_handle, "bytehook_hook_all");
|
||||||
|
bytehook_init_p = dlsym(bytehook_handle, "bytehook_init");
|
||||||
|
|
||||||
|
if(bytehook_hook_all_p == NULL || bytehook_init_p == NULL) {
|
||||||
|
goto dlerror;
|
||||||
|
}
|
||||||
|
int bhook_status = bytehook_init_p(BYTEHOOK_MODE_AUTOMATIC, false);
|
||||||
|
if(bhook_status == BYTEHOOK_STATUS_CODE_OK) {
|
||||||
|
create_hooks(bytehook_hook_all_p);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
LOGE("bytehook_init failed (%i)", bhook_status);
|
||||||
|
dlclose(bytehook_handle);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlerror:
|
||||||
|
if(bytehook_handle != NULL) dlclose(bytehook_handle);
|
||||||
|
LOGE("Failed to load hook library: %s", dlerror());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_net_kdt_pojavlaunch_utils_JREUtils_initializeHooks(JNIEnv *env, jclass clazz) {
|
||||||
|
bool hooks_ready = init_hooks();
|
||||||
|
if(!hooks_ready) {
|
||||||
|
LOGE("Failed to initialize native hooks!");
|
||||||
|
}
|
||||||
|
// Always register atexit, because that's what we will call our exit from.
|
||||||
|
// We only use the hook to capture the exit code.
|
||||||
|
atexit(custom_atexit);
|
||||||
|
}
|
15
app_pojavlauncher/src/main/jni/native_hooks/native_hooks.h
Normal file
15
app_pojavlauncher/src/main/jni/native_hooks/native_hooks.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// Created by maks on 23.01.2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef POJAVLAUNCHER_NATIVE_HOOKS_H
|
||||||
|
#define POJAVLAUNCHER_NATIVE_HOOKS_H
|
||||||
|
|
||||||
|
#include <bytehook.h>
|
||||||
|
|
||||||
|
typedef bytehook_stub_t (*bytehook_hook_all_t)(const char *callee_path_name, const char *sym_name, void *new_func,
|
||||||
|
bytehook_hooked_t hooked, void *hooked_arg);
|
||||||
|
|
||||||
|
void create_chmod_hooks(bytehook_hook_all_t bytehook_hook_all_p);
|
||||||
|
|
||||||
|
#endif //POJAVLAUNCHER_NATIVE_HOOKS_H
|
@ -11,8 +11,6 @@ jobjectArray convert_from_char_array(JNIEnv *env, char **charArray, int num_rows
|
|||||||
void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray);
|
void free_char_array(JNIEnv *env, jobjectArray jstringArray, const char **charArray);
|
||||||
jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr);
|
jstring convertStringJVM(JNIEnv* srcEnv, JNIEnv* dstEnv, jstring srcStr);
|
||||||
|
|
||||||
void hookExec(JNIEnv *env);
|
|
||||||
void installLwjglDlopenHook(JNIEnv *env);
|
|
||||||
JNIEnv* get_attached_env(JavaVM* jvm);
|
JNIEnv* get_attached_env(JavaVM* jvm);
|
||||||
JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc);
|
JNIEXPORT jstring JNICALL Java_org_lwjgl_glfw_CallbackBridge_nativeClipboard(JNIEnv* env, jclass clazz, jint action, jbyteArray copySrc);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user