From 894f7b99c3a3840c7ea0a47bd09c2d80165c5752 Mon Sep 17 00:00:00 2001 From: Mis012 Date: Thu, 24 Nov 2022 16:09:42 +0100 Subject: [PATCH] inform Java about apk path; allow specifying port for jdwp debugging with JDWP_LISTEN env; hackily work around onWindowFocusChanged being called at a time where it causes some apps to crash --- src/api-impl-jni/defines.h | 5 +++-- src/main-executable/main.c | 37 ++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/api-impl-jni/defines.h b/src/api-impl-jni/defines.h index 18a8764a..6ee2b490 100644 --- a/src/api-impl-jni/defines.h +++ b/src/api-impl-jni/defines.h @@ -7,8 +7,8 @@ // these macros are a bit hacky, since they deliberately assume that env exists and refers to the JNI env -#define _PTR(ptr)((void*)(intptr_t)ptr) -#define _INTPTR(ptr)((jlong)(intptr_t)ptr) +#define _PTR(ptr)((void*)(intptr_t)(ptr)) +#define _INTPTR(ptr)((jlong)(intptr_t)(ptr)) #define _REF(obj)((*env)->NewGlobalRef(env, obj)) #define _CLASS(object) ((*env)->GetObjectClass(env, object)) #define _SUPER(object) ((*env)->GetSuperclass(env, object)) @@ -24,6 +24,7 @@ #define _GET_LONG_FIELD(object, field) ((*env)->GetLongField(env, object, _FIELD_ID(_CLASS(object), field, "J"))) #define _SET_INT_FIELD(object, field, value) ((*env)->SetIntField(env, object, _FIELD_ID(_CLASS(object), field, "I"), value)) #define _SET_STATIC_INT_FIELD(class, field, value) ((*env)->SetStaticIntField(env, class, _STATIC_FIELD_ID(class, field, "I"), value)) +#define _SET_STATIC_OBJ_FIELD(class, field, type, value) ((*env)->SetStaticObjectField(env, class, _STATIC_FIELD_ID(class, field, type), value)) #define _GET_INT_FIELD(object, field) ((*env)->GetIntField(env, object, _FIELD_ID(_CLASS(object), field, "I"))) #define _GET_BYTE_ARRAY_ELEMENTS(b_array) ((*env)->GetByteArrayElements(env, b_array, NULL)) #define _RELEASE_BYTE_ARRAY_ELEMENTS(b_array, buffer_ptr) ((*env)->ReleaseByteArrayElements(env, b_array, buffer_ptr, 0)) diff --git a/src/main-executable/main.c b/src/main-executable/main.c index 64c63dbc..9263cd94 100644 --- a/src/main-executable/main.c +++ b/src/main-executable/main.c @@ -59,13 +59,20 @@ char *construct_classpath(char *prefix, char **cp_array, size_t len) return result; } +#define JDWP_ARG "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=" + JNIEnv* create_vm(char *api_impl_jar, char *apk_classpath, char *microg_apk, char *api_impl_natives_dir, char *app_lib_dir) { JavaVM* jvm; JNIEnv* env; JavaVMInitArgs args; - JavaVMOption options[3]; + JavaVMOption options[4]; args.version = JNI_VERSION_1_6; args.nOptions = 3; + char jdwp_option_string[sizeof(JDWP_ARG) + 5] = JDWP_ARG;// 5 chars for port number, NULL byte is counted by sizeof + + const char* jdwp_port = getenv("JDWP_LISTEN"); + if(jdwp_port) + args.nOptions += 1; if(getenv("RUN_FROM_BUILDDIR")) { options[0].optionString = construct_classpath("-Djava.library.path=", (char *[]){"./", app_lib_dir}, 2); @@ -78,6 +85,10 @@ JNIEnv* create_vm(char *api_impl_jar, char *apk_classpath, char *microg_apk, cha // TODO: request resources.arsc from concrete apk instead of taking the first one in classpath options[1].optionString = construct_classpath("-Djava.class.path=", (char *[]){api_impl_jar, apk_classpath, microg_apk}, 3); options[2].optionString = "-verbose:jni"; + if(jdwp_port) { + strncat(jdwp_option_string, jdwp_port, 5); // 5 chars is enough for a port number, and won't overflow our array + options[3].optionString = jdwp_option_string; + } args.options = options; args.ignoreUnrecognized = JNI_FALSE; @@ -91,6 +102,19 @@ JNIEnv* create_vm(char *api_impl_jar, char *apk_classpath, char *microg_apk, cha return env; } +gboolean hacky_on_window_focus_changed_callback(JNIEnv *env) +{ + if(gtk_widget_get_width(window) != 0) { + (*env)->CallVoidMethod(env, handle_cache.apk_main_activity.object, handle_cache.apk_main_activity.onWindowFocusChanged, true); + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); + + return G_SOURCE_REMOVE; + } + + return G_SOURCE_CONTINUE; +} + // this is exported by the shim bionic linker void dl_parse_library_path(const char *path, char *delim); @@ -259,10 +283,14 @@ static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* h _SET_STATIC_INT_FIELD(display_class, "window_width", d->window_width); _SET_STATIC_INT_FIELD(display_class, "window_height", d->window_height); + // some apps need the apk path since they directly read their apk + jclass context_class = (*env)->FindClass(env, "android/content/Context"); + _SET_STATIC_OBJ_FIELD(context_class, "apk_path", "java/lang/String", _JSTRING(apk_classpath)); + FIXME__WIDTH = d->window_width; FIXME__HEIGHT = d->window_height; - window = gtk_application_window_new (app); + window = gtk_application_window_new(app); (*env)->CallVoidMethod(env, handle_cache.apk_main_activity.object, handle_cache.apk_main_activity.set_window, _INTPTR(window)); if((*env)->ExceptionCheck(env)) (*env)->ExceptionDescribe(env); @@ -306,9 +334,8 @@ static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* h if((*env)->ExceptionCheck(env)) (*env)->ExceptionDescribe(env); - (*env)->CallVoidMethod(env, handle_cache.apk_main_activity.object, handle_cache.apk_main_activity.onWindowFocusChanged, true); - if((*env)->ExceptionCheck(env)) - (*env)->ExceptionDescribe(env); + g_timeout_add(10, G_SOURCE_FUNC(hacky_on_window_focus_changed_callback), env); + jobject input_queue_callback = g_object_get_data(G_OBJECT(window), "input_queue_callback"); if(input_queue_callback) {