diff --git a/android/native/jni/input_autodetect.c b/android/native/jni/input_autodetect.c index 83b5340029..b44bed938f 100644 --- a/android/native/jni/input_autodetect.c +++ b/android/native/jni/input_autodetect.c @@ -20,51 +20,47 @@ static void input_autodetect_get_device_name(void *data, char *buf, size_t size, int id) { - struct android_app *android_app = (struct android_app*)data; - buf[0] = '\0'; + JNIEnv *env = jni_thread_getenv(); + if (!env) + return; - JavaVM *vm = android_app->activity->vm; - JNIEnv *env = NULL; - (*vm)->AttachCurrentThread(vm, &env, 0); + buf[0] = '\0'; jclass class = NULL; FIND_CLASS(env, class, "android/view/InputDevice"); if (!class) - goto end; + return; jmethodID method = NULL; GET_STATIC_METHOD_ID(env, method, class, "getDevice", "(I)Landroid/view/InputDevice;"); if (!method) - goto end; + return; jobject device = NULL; CALL_OBJ_STATIC_METHOD_PARAM(env, device, class, method, (jint)id); if (!device) { RARCH_ERR("Failed to find device for ID: %d\n", id); - goto end; + return; } jmethodID getName = NULL; GET_METHOD_ID(env, getName, class, "getName", "()Ljava/lang/String;"); if (!getName) - goto end; + return; jobject name = NULL; CALL_OBJ_METHOD(env, name, device, getName); if (!name) { RARCH_ERR("Failed to find name for device ID: %d\n", id); - goto end; + return; } const char *str = (*env)->GetStringUTFChars(env, name, 0); if (str) strlcpy(buf, str, size); (*env)->ReleaseStringUTFChars(env, name, str); - -end: - (*vm)->DetachCurrentThread(vm); } void input_autodetect_setup(void *data, char *msg, size_t sizeof_msg, unsigned port, unsigned id, int source, bool *primary) diff --git a/android/native/jni/jni_macros.h b/android/native/jni/jni_macros.h index 63d48e9f8e..6c50ef9693 100644 --- a/android/native/jni/jni_macros.h +++ b/android/native/jni/jni_macros.h @@ -21,8 +21,6 @@ struct jni_params { - JavaVM *java_vm; - JNIEnv *env; jobject class_obj; char class_name[128]; char method_name[128]; diff --git a/camera/android.c b/camera/android.c index 0fedf7011e..af9e116b83 100644 --- a/camera/android.c +++ b/camera/android.c @@ -27,8 +27,6 @@ typedef struct android_camera { - JNIEnv *env; - JavaVM *java_vm; jclass class; jmethodID onCameraInit; jmethodID onCameraFree; @@ -41,6 +39,7 @@ typedef struct android_camera static void *android_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) { + JNIEnv *env; (void)device; (void)width; (void)height; @@ -56,39 +55,39 @@ static void *android_camera_init(const char *device, uint64_t caps, unsigned wid if (!androidcamera) return NULL; - androidcamera->java_vm = (JavaVM*)android_app->activity->vm; - if ((*androidcamera->java_vm)->AttachCurrentThread(androidcamera->java_vm, &androidcamera->env, 0) != JNI_OK) + env = jni_thread_getenv(); + if (!env) return NULL; - GET_OBJECT_CLASS(androidcamera->env, androidcamera->class, android_app->activity->clazz); + GET_OBJECT_CLASS(env, androidcamera->class, android_app->activity->clazz); if (androidcamera->class == NULL) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraInit, androidcamera->class, "onCameraInit", "()V"); + GET_METHOD_ID(env, androidcamera->onCameraInit, androidcamera->class, "onCameraInit", "()V"); if (!androidcamera->onCameraInit) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraFree, androidcamera->class, "onCameraFree", "()V"); + GET_METHOD_ID(env, androidcamera->onCameraFree, androidcamera->class, "onCameraFree", "()V"); if (!androidcamera->onCameraFree) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraSetTexture, androidcamera->class, "onCameraSetTexture", "(I)V"); + GET_METHOD_ID(env, androidcamera->onCameraSetTexture, androidcamera->class, "onCameraSetTexture", "(I)V"); if (!androidcamera->onCameraSetTexture) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraStart, androidcamera->class, "onCameraStart", "()V"); + GET_METHOD_ID(env, androidcamera->onCameraStart, androidcamera->class, "onCameraStart", "()V"); if (!androidcamera->onCameraStart) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraStop, androidcamera->class, "onCameraStop", "()V"); + GET_METHOD_ID(env, androidcamera->onCameraStop, androidcamera->class, "onCameraStop", "()V"); if (!androidcamera->onCameraStop) return NULL; - GET_METHOD_ID(androidcamera->env, androidcamera->onCameraPoll, androidcamera->class, "onCameraPoll", "()Z"); + GET_METHOD_ID(env, androidcamera->onCameraPoll, androidcamera->class, "onCameraPoll", "()Z"); if (!androidcamera->onCameraPoll) return NULL; - CALL_VOID_METHOD(androidcamera->env, android_app->activity->clazz, androidcamera->onCameraInit); + CALL_VOID_METHOD(env, android_app->activity->clazz, androidcamera->onCameraInit); return androidcamera; } @@ -97,11 +96,11 @@ static void android_camera_free(void *data) { struct android_app *android_app = (struct android_app*)g_android; androidcamera_t *androidcamera = (androidcamera_t*)data; - (void)android_app; + JNIEnv *env = jni_thread_getenv(); + if (!env) + return; - CALL_VOID_METHOD(androidcamera->env, android_app->activity->clazz, androidcamera->onCameraFree); - - (*androidcamera->java_vm)->DetachCurrentThread(androidcamera->java_vm); + CALL_VOID_METHOD(env, android_app->activity->clazz, androidcamera->onCameraFree); free(androidcamera); } @@ -110,9 +109,9 @@ static bool android_camera_start(void *data) { struct android_app *android_app = (struct android_app*)g_android; androidcamera_t *androidcamera = (androidcamera_t*)data; - - (void)android_app; - (void)androidcamera; + JNIEnv *env = jni_thread_getenv(); + if (!env) + return NULL; glGenTextures(1, &androidcamera->tex); glBindTexture(GL_TEXTURE_EXTERNAL_OES, androidcamera->tex); @@ -121,9 +120,8 @@ static bool android_camera_start(void *data) glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - CALL_VOID_METHOD_PARAM(androidcamera->env, android_app->activity->clazz, androidcamera->onCameraSetTexture, (int) androidcamera->tex); - - CALL_VOID_METHOD(androidcamera->env, android_app->activity->clazz, androidcamera->onCameraStart); + CALL_VOID_METHOD_PARAM(env, android_app->activity->clazz, androidcamera->onCameraSetTexture, (int) androidcamera->tex); + CALL_VOID_METHOD(env, android_app->activity->clazz, androidcamera->onCameraStart); return true; } @@ -132,10 +130,11 @@ static void android_camera_stop(void *data) { struct android_app *android_app = (struct android_app*)g_android; androidcamera_t *androidcamera = (androidcamera_t*)data; - (void)android_app; - (void)androidcamera; + JNIEnv *env = jni_thread_getenv(); + if (!env) + return; - CALL_VOID_METHOD(androidcamera->env, android_app->activity->clazz, androidcamera->onCameraStop); + CALL_VOID_METHOD(env, android_app->activity->clazz, androidcamera->onCameraStop); if (androidcamera->tex) glDeleteTextures(1, &androidcamera->tex); @@ -146,12 +145,14 @@ static bool android_camera_poll(void *data, retro_camera_frame_raw_framebuffer_t { struct android_app *android_app = (struct android_app*)g_android; androidcamera_t *androidcamera = (androidcamera_t*)data; - (void)android_app; - (void)androidcamera; + JNIEnv *env = jni_thread_getenv(); + if (!env) + return NULL; + (void)frame_raw_cb; jboolean newFrame; - CALL_BOOLEAN_METHOD(androidcamera->env, newFrame, android_app->activity->clazz, androidcamera->onCameraPoll); + CALL_BOOLEAN_METHOD(env, newFrame, android_app->activity->clazz, androidcamera->onCameraPoll); if (newFrame) { diff --git a/frontend/platform/platform_android.c b/frontend/platform/platform_android.c index 30cc42d88c..c1f1e89ca9 100644 --- a/frontend/platform/platform_android.c +++ b/frontend/platform/platform_android.c @@ -29,6 +29,7 @@ #include "../../file.h" struct android_app *g_android; +static pthread_key_t thread_key; //forward decls static void system_deinit(void *data); @@ -161,6 +162,33 @@ static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) android_app_set_input((struct android_app*)activity->instance, NULL); } +JNIEnv *jni_thread_getenv(void) +{ + struct android_app* android_app = (struct android_app*)g_android; + JNIEnv *env; + int status = (*android_app->activity->vm)->AttachCurrentThread(android_app->activity->vm, &env, 0); + if (status < 0) + { + RARCH_ERR("jni_thread_getenv: Failed to attach current thread.\n"); + return NULL; + } + pthread_setspecific(thread_key, (void*)env); + + return env; +} + +static void jni_thread_destruct(void *value) +{ + struct android_app* android_app = (struct android_app*)g_android; + JNIEnv *env = (JNIEnv*)value; + if (env) + { + if (android_app) + (*android_app->activity->vm)->DetachCurrentThread(android_app->activity->vm); + pthread_setspecific(thread_key, NULL); + } +} + // -------------------------------------------------------------------- // Native activity interaction (called from main thread) // -------------------------------------------------------------------- @@ -189,6 +217,9 @@ void ANativeActivity_onCreate(ANativeActivity* activity, // these are set only for the native activity, and are reset when it ends ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON | AWINDOW_FLAG_FULLSCREEN, 0); + if (pthread_key_create(&thread_key, jni_thread_destruct)) + RARCH_ERR("Error initializing pthread_key\n"); + struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); memset(android_app, 0, sizeof(struct android_app)); android_app->activity = activity; @@ -230,8 +261,10 @@ static bool android_run_events (void *data) return true; } -static void jni_get (void *data_in, void *data_out) +static void jni_get(void *data, void *data_in, void *data_out) { + JNIEnv *env; + struct android_app* android_app = (struct android_app*)data; struct jni_params *in_params = (struct jni_params*)data_in; struct jni_out_params_char *out_args = (struct jni_out_params_char*)data_out; jclass class = NULL; @@ -239,24 +272,31 @@ static void jni_get (void *data_in, void *data_out) jmethodID giid = NULL; jstring ret; - GET_OBJECT_CLASS(in_params->env, class, in_params->class_obj); - GET_METHOD_ID(in_params->env, giid, class, in_params->method_name, in_params->method_signature); - CALL_OBJ_METHOD(in_params->env, obj, in_params->class_obj, giid); + if (!android_app) + return; + + env = jni_thread_getenv(); + if (!env) + return; + + GET_OBJECT_CLASS(env, class, in_params->class_obj); + GET_METHOD_ID(env, giid, class, in_params->method_name, in_params->method_signature); + CALL_OBJ_METHOD(env, obj, in_params->class_obj, giid); if (in_params->submethod_name && in_params->submethod_signature) { - GET_OBJECT_CLASS(in_params->env, class, obj); - GET_METHOD_ID(in_params->env, giid, class, in_params->submethod_name, in_params->submethod_signature); + GET_OBJECT_CLASS(env, class, obj); + GET_METHOD_ID(env, giid, class, in_params->submethod_name, in_params->submethod_signature); - CALL_OBJ_METHOD_PARAM(in_params->env, ret, obj, giid, (*in_params->env)->NewStringUTF(in_params->env, out_args->in)); + CALL_OBJ_METHOD_PARAM(env, ret, obj, giid, (*env)->NewStringUTF(env, out_args->in)); } if (giid && ret) { - const char *argv = (*in_params->env)->GetStringUTFChars(in_params->env, ret, 0); + const char *argv = (*env)->GetStringUTFChars(env, ret, 0); strlcpy(out_args->out, argv, out_args->out_sizeof); - (*in_params->env)->ReleaseStringUTFChars(in_params->env, ret, argv); + (*env)->ReleaseStringUTFChars(env, ret, argv); } } @@ -267,7 +307,6 @@ static void get_environment_settings(int argc, char *argv[], void *data) struct jni_params in_params; struct jni_out_params_char out_args; - in_params.java_vm = android_app->activity->vm; in_params.class_obj = android_app->activity->clazz; strlcpy(in_params.method_name, "getIntent", sizeof(in_params.method_name)); @@ -275,25 +314,24 @@ static void get_environment_settings(int argc, char *argv[], void *data) strlcpy(in_params.submethod_name, "getStringExtra", sizeof(in_params.submethod_name)); strlcpy(in_params.submethod_signature, "(Ljava/lang/String;)Ljava/lang/String;", sizeof(in_params.submethod_signature)); - (*in_params.java_vm)->AttachCurrentThread(in_params.java_vm, &in_params.env, 0); // ROM out_args.out = g_extern.fullpath; out_args.out_sizeof = sizeof(g_extern.fullpath); strlcpy(out_args.in, "ROM", sizeof(out_args.in)); - jni_get(&in_params, &out_args); + jni_get(android_app, &in_params, &out_args); // Config file out_args.out = g_extern.config_path; out_args.out_sizeof = sizeof(g_extern.config_path); strlcpy(out_args.in, "CONFIGFILE", sizeof(out_args.in)); - jni_get(&in_params, &out_args); + jni_get(android_app, &in_params, &out_args); // Current IME out_args.out = android_app->current_ime; out_args.out_sizeof = sizeof(android_app->current_ime); strlcpy(out_args.in, "IME", sizeof(out_args.in)); - jni_get(&in_params, &out_args); + jni_get(android_app, &in_params, &out_args); RARCH_LOG("Checking arguments passed ...\n"); RARCH_LOG("ROM Filename: [%s].\n", g_extern.fullpath); @@ -306,12 +344,10 @@ static void get_environment_settings(int argc, char *argv[], void *data) out_args.out = g_settings.libretro; out_args.out_sizeof = sizeof(g_settings.libretro); strlcpy(out_args.in, "LIBRETRO", sizeof(out_args.in)); - jni_get(&in_params, &out_args); + jni_get(android_app, &in_params, &out_args); RARCH_LOG("Checking arguments passed ...\n"); RARCH_LOG("Libretro path: [%s].\n", g_settings.libretro); - - (*in_params.java_vm)->DetachCurrentThread(in_params.java_vm); } static int process_events(void *data) diff --git a/frontend/platform/platform_android.h b/frontend/platform/platform_android.h index f9d2a12448..73828803dc 100644 --- a/frontend/platform/platform_android.h +++ b/frontend/platform/platform_android.h @@ -148,6 +148,7 @@ enum { }; extern void engine_handle_cmd(void); +extern JNIEnv *jni_thread_getenv(void); extern struct android_app *g_android;