ANDROID: Store JNI environment in a thread local variable

This avoids to query JVM every time we need to do a JNI call.
A different environment is attached to each thread, hence the TLS
variable.
This commit is contained in:
Le Philousophe 2023-01-08 11:41:59 +01:00
parent 54fd20c36c
commit e17b34c9dc
3 changed files with 40 additions and 9 deletions

View file

@ -24,6 +24,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include "backends/platform/android/jni-android.h"
#include "backends/platform/android/asset-archive.h"
#include "common/str.h" #include "common/str.h"
#include "common/stream.h" #include "common/stream.h"
#include "common/util.h" #include "common/util.h"
@ -31,12 +37,6 @@
#include "common/debug.h" #include "common/debug.h"
#include "common/textconsole.h" #include "common/textconsole.h"
#include "backends/platform/android/jni-android.h"
#include "backends/platform/android/asset-archive.h"
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
class AssetInputStream : public Common::SeekableReadStream { class AssetInputStream : public Common::SeekableReadStream {
public: public:
AssetInputStream(AAssetManager *as, const Common::String &path); AssetInputStream(AAssetManager *as, const Common::String &path);

View file

@ -58,6 +58,8 @@ jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return JNI::onLoad(vm); return JNI::onLoad(vm);
} }
pthread_key_t JNI::_env_tls;
JavaVM *JNI::_vm = 0; JavaVM *JNI::_vm = 0;
jobject JNI::_jobj = 0; jobject JNI::_jobj = 0;
jobject JNI::_jobj_audio_track = 0; jobject JNI::_jobj_audio_track = 0;
@ -141,6 +143,10 @@ JNI::~JNI() {
} }
jint JNI::onLoad(JavaVM *vm) { jint JNI::onLoad(JavaVM *vm) {
if (pthread_key_create(&_env_tls, NULL)) {
return JNI_ERR;
}
_vm = vm; _vm = vm;
JNIEnv *env; JNIEnv *env;
@ -148,6 +154,10 @@ jint JNI::onLoad(JavaVM *vm) {
if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2)) if (_vm->GetEnv((void **)&env, JNI_VERSION_1_2))
return JNI_ERR; return JNI_ERR;
if (pthread_setspecific(_env_tls, env)) {
return JNI_ERR;
}
jclass cls = env->FindClass("org/scummvm/scummvm/ScummVM"); jclass cls = env->FindClass("org/scummvm/scummvm/ScummVM");
if (cls == 0) if (cls == 0)
return JNI_ERR; return JNI_ERR;
@ -158,8 +168,8 @@ jint JNI::onLoad(JavaVM *vm) {
return JNI_VERSION_1_2; return JNI_VERSION_1_2;
} }
JNIEnv *JNI::getEnv() { JNIEnv *JNI::fetchEnv() {
JNIEnv *env = 0; JNIEnv *env;
jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2); jint res = _vm->GetEnv((void **)&env, JNI_VERSION_1_2);
@ -168,6 +178,8 @@ JNIEnv *JNI::getEnv() {
abort(); abort();
} }
pthread_setspecific(_env_tls, env);
return env; return env;
} }
@ -180,9 +192,16 @@ void JNI::attachThread() {
LOGE("AttachCurrentThread() failed: %d", res); LOGE("AttachCurrentThread() failed: %d", res);
abort(); abort();
} }
if (pthread_setspecific(_env_tls, env)) {
LOGE("pthread_setspecific() failed");
abort();
}
} }
void JNI::detachThread() { void JNI::detachThread() {
pthread_setspecific(_env_tls, NULL);
jint res = _vm->DetachCurrentThread(); jint res = _vm->DetachCurrentThread();
if (res != JNI_OK) { if (res != JNI_OK) {

View file

@ -26,6 +26,7 @@
#include <jni.h> #include <jni.h>
#include <semaphore.h> #include <semaphore.h>
#include <pthread.h>
#include "common/fs.h" #include "common/fs.h"
#include "common/archive.h" #include "common/archive.h"
@ -59,7 +60,14 @@ public:
static jint onLoad(JavaVM *vm); static jint onLoad(JavaVM *vm);
static JNIEnv *getEnv(); static inline JNIEnv *getEnv() {
JNIEnv *env = (JNIEnv*) pthread_getspecific(_env_tls);
if (env != nullptr) {
return env;
}
return fetchEnv();
}
static void attachThread(); static void attachThread();
static void detachThread(); static void detachThread();
@ -102,6 +110,8 @@ public:
static bool isDirectoryWritableWithSAF(const Common::String &dirPath); static bool isDirectoryWritableWithSAF(const Common::String &dirPath);
private: private:
static pthread_key_t _env_tls;
static JavaVM *_vm; static JavaVM *_vm;
// back pointer to (java) peer instance // back pointer to (java) peer instance
static jobject _jobj; static jobject _jobj;
@ -172,6 +182,8 @@ private:
static Common::U32String convertFromJString(JNIEnv *env, const jstring &jstr); static Common::U32String convertFromJString(JNIEnv *env, const jstring &jstr);
static PauseToken _pauseToken; static PauseToken _pauseToken;
static JNIEnv *fetchEnv();
}; };
inline bool JNI::haveSurface() { inline bool JNI::haveSurface() {