Clean up JNI: (...)

* pthread_key_create is used to set a destructor for every thread
created through jni_thread_getenv
* To grab a JNIEnv pointer - go through jni_thread_getenv
* jni_thread_getenv sets pthread_setspecific for the JNIEnv pointer
to bind destructor
* Reuse activity->vm everywhere instead of creating local pointer
copies
* Don't use DetachCurrentThread outside of platform_android's (new)
jni_thread_destruct function - the destructor will do this for us
now
This commit is contained in:
twinaphex 2013-11-20 17:33:19 +01:00
parent 3f279a2d5c
commit 87421d477c
5 changed files with 92 additions and 60 deletions

View File

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

View File

@ -21,8 +21,6 @@
struct jni_params
{
JavaVM *java_vm;
JNIEnv *env;
jobject class_obj;
char class_name[128];
char method_name[128];

View File

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

View File

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

View File

@ -148,6 +148,7 @@ enum {
};
extern void engine_handle_cmd(void);
extern JNIEnv *jni_thread_getenv(void);
extern struct android_app *g_android;