103 lines
3.8 KiB
C
103 lines
3.8 KiB
C
|
|
#include <pthread.h>
|
|
#include <jni.h>
|
|
|
|
#define LOGI(...) do {} while (0)
|
|
#define LOGE(...) do {} while (0)
|
|
|
|
#include "android/log.h"
|
|
|
|
/* These JNI management functions are taken from SDL2, but modified to refer to pyjnius */
|
|
|
|
/* #define LOG(n, x) __android_log_write(ANDROID_LOG_INFO, (n), (x)) */
|
|
/* #define LOGP(x) LOG("python", (x)) */
|
|
#define LOG_TAG "Python_android"
|
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
|
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
|
|
|
|
|
/* Function headers */
|
|
JNIEnv* Android_JNI_GetEnv(void);
|
|
static void Android_JNI_ThreadDestroyed(void*);
|
|
|
|
static pthread_key_t mThreadKey;
|
|
static JavaVM* mJavaVM;
|
|
|
|
int Android_JNI_SetupThread(void)
|
|
{
|
|
Android_JNI_GetEnv();
|
|
return 1;
|
|
}
|
|
|
|
/* Library init */
|
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
|
|
{
|
|
JNIEnv *env;
|
|
mJavaVM = vm;
|
|
LOGI("JNI_OnLoad called");
|
|
if ((*mJavaVM)->GetEnv(mJavaVM, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
|
|
LOGE("Failed to get the environment using GetEnv()");
|
|
return -1;
|
|
}
|
|
/*
|
|
* Create mThreadKey so we can keep track of the JNIEnv assigned to each thread
|
|
* Refer to http://developer.android.com/guide/practices/design/jni.html for the rationale behind this
|
|
*/
|
|
if (pthread_key_create(&mThreadKey, Android_JNI_ThreadDestroyed) != 0) {
|
|
|
|
__android_log_print(ANDROID_LOG_ERROR, "pyjniusjni", "Error initializing pthread key");
|
|
}
|
|
Android_JNI_SetupThread();
|
|
|
|
return JNI_VERSION_1_4;
|
|
}
|
|
|
|
JNIEnv* Android_JNI_GetEnv(void)
|
|
{
|
|
/* From http://developer.android.com/guide/practices/jni.html
|
|
* All threads are Linux threads, scheduled by the kernel.
|
|
* They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
|
|
* attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
|
|
* JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
|
|
* and cannot make JNI calls.
|
|
* Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
|
|
* ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
|
|
* is a no-op.
|
|
* Note: You can call this function any number of times for the same thread, there's no harm in it
|
|
*/
|
|
|
|
JNIEnv *env;
|
|
int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
|
|
if(status < 0) {
|
|
LOGE("failed to attach current thread");
|
|
return 0;
|
|
}
|
|
|
|
/* From http://developer.android.com/guide/practices/jni.html
|
|
* Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
|
|
* in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
|
|
* called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
|
|
* to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
|
|
* Note: The destructor is not called unless the stored value is != NULL
|
|
* Note: You can call this function any number of times for the same thread, there's no harm in it
|
|
* (except for some lost CPU cycles)
|
|
*/
|
|
pthread_setspecific(mThreadKey, (void*) env);
|
|
|
|
return env;
|
|
}
|
|
|
|
static void Android_JNI_ThreadDestroyed(void* value)
|
|
{
|
|
/* The thread is being destroyed, detach it from the Java VM and set the mThreadKey value to NULL as required */
|
|
JNIEnv *env = (JNIEnv*) value;
|
|
if (env != NULL) {
|
|
(*mJavaVM)->DetachCurrentThread(mJavaVM);
|
|
pthread_setspecific(mThreadKey, NULL);
|
|
}
|
|
}
|
|
|
|
void *WebView_AndroidGetJNIEnv()
|
|
{
|
|
return Android_JNI_GetEnv();
|
|
}
|