Android: move and group JNIEnv helper functions
authorSylvain Becker <sylvain.becker@gmail.com>
Fri, 11 Jan 2019 21:52:43 +0100
changeset 1253063abc8d1ca3a
parent 12529 86c22cfe2d7d
child 12531 af47ff0de5ab
Android: move and group JNIEnv helper functions
src/core/android/SDL_android.c
     1.1 --- a/src/core/android/SDL_android.c	Fri Jan 11 21:42:52 2019 +0100
     1.2 +++ b/src/core/android/SDL_android.c	Fri Jan 11 21:52:43 2019 +0100
     1.3 @@ -46,12 +46,6 @@
     1.4  #include <sys/types.h>
     1.5  #include <unistd.h>
     1.6  #include <dlfcn.h>
     1.7 -/* #define LOG_TAG "SDL_android" */
     1.8 -/* #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) */
     1.9 -/* #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) */
    1.10 -#define LOGI(...) do {} while (0)
    1.11 -#define LOGE(...) do {} while (0)
    1.12 -
    1.13  
    1.14  #define SDL_JAVA_PREFIX                                 org_libsdl_app
    1.15  #define CONCAT1(prefix, class, function)                CONCAT2(prefix, class, function)
    1.16 @@ -212,7 +206,6 @@
    1.17  /* Uncomment this to log messages entering and exiting methods in this file */
    1.18  /* #define DEBUG_JNI */
    1.19  
    1.20 -static void Android_JNI_ThreadDestroyed(void *);
    1.21  static void checkJNIReady(void);
    1.22  
    1.23  /*******************************************************************************
    1.24 @@ -293,13 +286,95 @@
    1.25  
    1.26  static SDL_bool bHasEnvironmentVariables = SDL_FALSE;
    1.27  
    1.28 -
    1.29 -static int Android_JNI_SetEnv(JNIEnv *env);
    1.30 -
    1.31  /*******************************************************************************
    1.32                   Functions called by JNI
    1.33  *******************************************************************************/
    1.34  
    1.35 +/* From http://developer.android.com/guide/practices/jni.html
    1.36 + * All threads are Linux threads, scheduled by the kernel.
    1.37 + * They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
    1.38 + * attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
    1.39 + * JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
    1.40 + * and cannot make JNI calls.
    1.41 + * Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
    1.42 + * ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
    1.43 + * is a no-op.
    1.44 + * Note: You can call this function any number of times for the same thread, there's no harm in it
    1.45 + */
    1.46 +
    1.47 +/* From http://developer.android.com/guide/practices/jni.html
    1.48 + * Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
    1.49 + * in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
    1.50 + * called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
    1.51 + * to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
    1.52 + * Note: The destructor is not called unless the stored value is != NULL
    1.53 + * Note: You can call this function any number of times for the same thread, there's no harm in it
    1.54 + *       (except for some lost CPU cycles)
    1.55 + */
    1.56 +
    1.57 +/* Set local storage value */
    1.58 +static int
    1.59 +Android_JNI_SetEnv(JNIEnv *env) {
    1.60 +    int status = pthread_setspecific(mThreadKey, env);
    1.61 +    if (status < 0) {
    1.62 +        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed pthread_setspecific() in Android_JNI_SetEnv() (err=%d)", status);
    1.63 +    }
    1.64 +    return status;
    1.65 +}
    1.66 +
    1.67 +/* Get local storage value */
    1.68 +JNIEnv* Android_JNI_GetEnv(void)
    1.69 +{
    1.70 +    /* Get JNIEnv from the Thread local storage */
    1.71 +    JNIEnv *env = pthread_getspecific(mThreadKey);
    1.72 +    if (env == NULL) {
    1.73 +        __android_log_print(ANDROID_LOG_ERROR, "SDL", "JNIEnv is NULL. Call Android_JNI_SetupThread() first.");
    1.74 +    }
    1.75 +
    1.76 +    return env;
    1.77 +}
    1.78 +
    1.79 +/* Set up an external thread for using JNI with Android_JNI_GetEnv() */
    1.80 +int Android_JNI_SetupThread(void)
    1.81 +{
    1.82 +    JNIEnv *env;
    1.83 +    int status;
    1.84 +
    1.85 +    /* There should be a JVM */
    1.86 +    if (mJavaVM == NULL) {
    1.87 +        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
    1.88 +        return 0;
    1.89 +    }
    1.90 +
    1.91 +    /* Attach the current thread to the JVM and get a JNIEnv.
    1.92 +     * It will be detached by pthread_create destructor 'Android_JNI_ThreadDestroyed' */
    1.93 +    status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
    1.94 +    if (status < 0) {
    1.95 +        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to attach current thread (err=%d)", status);
    1.96 +        return 0;
    1.97 +    }
    1.98 +
    1.99 +    /* Save JNIEnv into the Thread local storage */
   1.100 +    if (Android_JNI_SetEnv(env) < 0) {
   1.101 +        return 0;
   1.102 +    }
   1.103 +
   1.104 +    return 1;
   1.105 +}
   1.106 +
   1.107 +/* Destructor called for each thread where mThreadKey is not NULL */
   1.108 +static void
   1.109 +Android_JNI_ThreadDestroyed(void *value)
   1.110 +{
   1.111 +    /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
   1.112 +    JNIEnv *env = (JNIEnv *) value;
   1.113 +    if (env != NULL) {
   1.114 +        (*mJavaVM)->DetachCurrentThread(mJavaVM);
   1.115 +        Android_JNI_SetEnv(NULL);
   1.116 +    }
   1.117 +}
   1.118 +
   1.119 +/* Creation of local storage mThreadKey */
   1.120  static void
   1.121  Android_JNI_CreateKey()
   1.122  {
   1.123 @@ -309,7 +384,7 @@
   1.124      }
   1.125  }
   1.126  
   1.127 -static void 
   1.128 +static void
   1.129  Android_JNI_CreateKey_once()
   1.130  {
   1.131      int status = pthread_once(&key_once, Android_JNI_CreateKey);
   1.132 @@ -576,7 +651,7 @@
   1.133      }
   1.134      (*env)->ReleaseStringUTFChars(env, library, library_file);
   1.135  
   1.136 -    /* This is a Java thread, it doesn't need to be Detached from the JVM. 
   1.137 +    /* This is a Java thread, it doesn't need to be Detached from the JVM.
   1.138       * Set to mThreadKey value to NULL not to call pthread_create destructor 'Android_JNI_ThreadDestroyed' */
   1.139      Android_JNI_SetEnv(NULL);
   1.140  
   1.141 @@ -888,7 +963,7 @@
   1.142  
   1.143      str = SDL_GetError();
   1.144      if (str && str[0]) {
   1.145 -        __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDLActivity thread ends (error=%s)", str);
   1.146 +        __android_log_print(ANDROID_LOG_ERROR, "SDL", "SDLActivity thread ends (error=%s)", str);
   1.147      } else {
   1.148          __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDLActivity thread ends");
   1.149      }
   1.150 @@ -1141,87 +1216,6 @@
   1.151      return retval;
   1.152  }
   1.153  
   1.154 -static void Android_JNI_ThreadDestroyed(void *value)
   1.155 -{
   1.156 -    /* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
   1.157 -    JNIEnv *env = (JNIEnv *) value;
   1.158 -    if (env != NULL) {
   1.159 -        (*mJavaVM)->DetachCurrentThread(mJavaVM);
   1.160 -        Android_JNI_SetEnv(NULL);
   1.161 -    }
   1.162 -}
   1.163 -
   1.164 -static int Android_JNI_SetEnv(JNIEnv *env) {
   1.165 -    int status = pthread_setspecific(mThreadKey, env);
   1.166 -    if (status < 0) {
   1.167 -        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed pthread_setspecific() in Android_JNI_SetEnv() (err=%d)", status);
   1.168 -    }
   1.169 -    return status;
   1.170 -}
   1.171 -
   1.172 -JNIEnv* Android_JNI_GetEnv(void)
   1.173 -{
   1.174 -    /* From http://developer.android.com/guide/practices/jni.html
   1.175 -     * All threads are Linux threads, scheduled by the kernel.
   1.176 -     * They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
   1.177 -     * attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
   1.178 -     * JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
   1.179 -     * and cannot make JNI calls.
   1.180 -     * Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
   1.181 -     * ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
   1.182 -     * is a no-op.
   1.183 -     * Note: You can call this function any number of times for the same thread, there's no harm in it
   1.184 -     */
   1.185 -
   1.186 -    /* From http://developer.android.com/guide/practices/jni.html
   1.187 -     * Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
   1.188 -     * in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
   1.189 -     * called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
   1.190 -     * to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
   1.191 -     * Note: The destructor is not called unless the stored value is != NULL
   1.192 -     * Note: You can call this function any number of times for the same thread, there's no harm in it
   1.193 -     *       (except for some lost CPU cycles)
   1.194 -     */
   1.195 -
   1.196 -
   1.197 -
   1.198 -    /* Get JNIEnv from the Thread local storage */
   1.199 -    JNIEnv *env = pthread_getspecific(mThreadKey);
   1.200 -    if (env == NULL) {
   1.201 -        __android_log_print(ANDROID_LOG_ERROR, "SDL", "JNIEnv is NULL. Call Android_JNI_SetupThread() first.");
   1.202 -    }
   1.203 -
   1.204 -    return env;
   1.205 -}
   1.206 -
   1.207 -int Android_JNI_SetupThread(void)
   1.208 -{
   1.209 -    JNIEnv *env;
   1.210 -    int status;
   1.211 -
   1.212 -    /* There should be a JVM */
   1.213 -    if (mJavaVM == NULL) {
   1.214 -        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed, there is no JavaVM");
   1.215 -        return 0;
   1.216 -    }
   1.217 -
   1.218 -    /* Attach the current thread to the JVM and get a JNIEnv.
   1.219 -     * It will be detached by pthread_create destructor 'Android_JNI_ThreadDestroyed'
   1.220 -     */
   1.221 -    status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
   1.222 -    if (status < 0) {
   1.223 -        __android_log_print(ANDROID_LOG_ERROR, "SDL", "Failed to attach current thread (err=%d)", status);
   1.224 -        return 0;
   1.225 -    }
   1.226 -
   1.227 -    /* Save JNIEnv into the Thread local storage */
   1.228 -    if (Android_JNI_SetEnv(env) < 0) {
   1.229 -        return 0;
   1.230 -    }
   1.231 -
   1.232 -    return 1;
   1.233 -}
   1.234 -
   1.235  /*
   1.236   * Audio support
   1.237   */