[android] JNI refactoring, automatic thread attach/detach, fixed crash with non-attached threads for threaded GLRenderer Implementation

This commit is contained in:
Alex Zolotarev 2012-04-11 15:52:20 +03:00 committed by Alex Zolotarev
parent b8baaca8c3
commit b2e91cf67e
24 changed files with 198 additions and 430 deletions

View file

@ -12,7 +12,6 @@ TARGET_PLATFORM := android-5
LOCAL_HEADER_FILES := \
com/mapswithme/core/jni_helper.hpp \
com/mapswithme/core/jni_string.hpp \
com/mapswithme/core/logging.hpp \
com/mapswithme/core/render_context.hpp \
com/mapswithme/maps/Framework.hpp \
@ -26,7 +25,6 @@ LOCAL_HEADER_FILES := \
LOCAL_SRC_FILES := \
com/mapswithme/core/jni_helper.cpp \
com/mapswithme/core/jni_string.cpp \
com/mapswithme/core/logging.cpp \
com/mapswithme/core/render_context.cpp \
com/mapswithme/maps/DownloadUI.cpp \
@ -38,8 +36,7 @@ LOCAL_SRC_FILES := \
com/mapswithme/platform/Platform.cpp \
com/mapswithme/platform/HttpThread.cpp \
com/mapswithme/platform/Language.cpp \
com/mapswithme/jni/jni_thread.cpp \
com/mapswithme/jni/jni_method.cpp \
com/mapswithme/platform/PThreadImpl.cpp \
nv_thread/nv_thread.cpp \
nv_event/nv_event_queue.cpp \
nv_event/nv_event.cpp \

View file

@ -1,21 +1,76 @@
#include "jni_helper.hpp"
#include "logging.hpp"
#include "../../../../../base/assert.hpp"
static JavaVM * g_jvm = 0;
namespace jni {
// @TODO remove after refactoring. Needed for NVidia code
void InitNVEvent(JavaVM * jvm);
// Some examples of sig:
// "()V" - void function returning void;
// "(Ljava/lang/String;)V" - String function returning void;
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj,
char const * fn, char const * sig)
extern "C"
{
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM * jvm, void *)
{
ASSERT ( env != 0 && obj != 0, () );
g_jvm = jvm;
jni::InitSystemLog();
jni::InitAssertLog();
// @TODO remove line below after refactoring
InitNVEvent(jvm);
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *, void *)
{
g_jvm = 0;
}
} // extern "C"
namespace jni
{
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig)
{
ASSERT(env, ("JNIEnv can't be 0"));
ASSERT(obj, ("jobject can't be 0"));
jclass cls = env->GetObjectClass(obj);
ASSERT(cls, ("Can't get java class"));
jmethodID mid = env->GetMethodID(cls, fn, sig);
ASSERT ( mid != 0, () );
ASSERT(mid, ("Can't find java method", fn, sig));
return mid;
}
}
string ToString(JNIEnv * env, jstring str)
{
string result;
char const * utfBuffer = env->GetStringUTFChars(str, 0);
if (utfBuffer)
{
result = utfBuffer;
env->ReleaseStringUTFChars(str, utfBuffer);
}
return result;
}
JNIEnv * GetEnv()
{
JNIEnv * env;
if (JNI_OK != g_jvm->GetEnv((void **)&env, JNI_VERSION_1_6))
{
ASSERT(false, ("Can't get JNIEnv. Was thread attached to JVM?"));
return 0;
}
return env;
}
JavaVM * GetJVM()
{
ASSERT(g_jvm, ("JVM is not initialized"));
return g_jvm;
}
} // namespace jni

View file

@ -2,28 +2,15 @@
#include <jni.h>
#include "../../../../../std/string.hpp"
namespace jni
{
// Some examples of sig:
// "()V" - void function returning void;
// "(Ljava/lang/String;)V" - String function returning void;
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj,
char const * fn, char const * sig);
/* Example of usage:
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MWMActivity_callbackFromJNI(JNIEnv * env, jobject thiz)
{
LOG("Enter callbackFromJNI");
env->CallVoidMethod(thiz,
jni::GetJavaMethodID(env, thiz, "callbackVoid", "()V"));
env->CallVoidMethod(
thiz,
jni::GetJavaMethodID(env, thiz, "callbackString",
"(Ljava/lang/String;)V"), env->NewStringUTF("Pass string from JNI."));
LOG("Leave callbackFromJNI");
}
*/
jmethodID GetJavaMethodID(JNIEnv * env, jobject obj, char const * fn, char const * sig);
string ToString(JNIEnv * env, jstring str);
JNIEnv * GetEnv();
JavaVM * GetJVM();
}

View file

@ -1,33 +0,0 @@
#include "jni_string.hpp"
#include "../../../../../base/string_utils.hpp"
namespace jni
{
String::String(JNIEnv * env, jstring s)
: m_env(env), m_s(s)
{
m_ret = m_env->GetStringChars(m_s, NULL);
}
String::~String()
{
m_env->ReleaseStringChars(m_s, m_ret);
}
string String::ToString() const
{
size_t const sz = m_env->GetStringLength(m_s);
string res;
utf8::unchecked::utf16to8(m_ret, m_ret + sz, back_inserter(res));
return res;
}
string ToString(JNIEnv * env, jstring s)
{
return String(env, s).ToString();
}
}

View file

@ -1,23 +0,0 @@
#pragma once
#include <string.h>
#include <jni.h>
#include "../../../../../std/string.hpp"
namespace jni
{
class String
{
JNIEnv * m_env;
jstring m_s;
jchar const * m_ret;
public:
String(JNIEnv * env, jstring s);
~String();
string ToString() const;
};
string ToString(JNIEnv * env, jstring s);
}

View file

@ -3,8 +3,10 @@
#include <android/log.h>
#include "../../../../../base/assert.hpp"
#include "../../../../../base/logging.hpp"
namespace jni {
namespace jni
{
using namespace my;

View file

@ -1,7 +1,5 @@
#pragma once
#include "../../../../../base/logging.hpp"
namespace jni
{
void InitSystemLog();

View file

@ -1,58 +0,0 @@
/*
* method_ref.cpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#include "jni_thread.hpp"
#include "jni_method.hpp"
#include "../../../../../base/assert.hpp"
namespace jni
{
Method::Method(jclass klass,
char const * name,
char const * signature)
: m_name(name),
m_signature(signature)
{
JNIEnv * env = GetCurrentThreadJNIEnv();
m_index = env->GetMethodID(klass, m_name, m_signature);
CHECK(m_index, ("Error: No valid function pointer in ", m_name));
}
Method::Method(jobject obj,
char const * name,
char const * signature)
: m_name(name),
m_signature(signature)
{
jclass k = GetCurrentThreadJNIEnv()->GetObjectClass(obj);
GetCurrentThreadJNIEnv()->GetMethodID(k, m_name, m_signature);
CHECK(m_index, ("Error: No valid function pointer in ", m_name));
}
bool Method::CallBoolean(jobject self)
{
JNIEnv* jniEnv = GetCurrentThreadJNIEnv();
CHECK(jniEnv, ("Error: No valid JNI env in ", m_name));
return jniEnv->CallBooleanMethod(self, m_index);
}
bool Method::CallInt(jobject self)
{
JNIEnv* jniEnv = GetCurrentThreadJNIEnv();
CHECK(jniEnv, ("Error: No valid JNI env in ", m_name));
return (int)jniEnv->CallIntMethod(self, m_index);
}
jmethodID Method::GetMethodID() const
{
return m_index;
}
}

View file

@ -1,73 +0,0 @@
/*
* method_ref.hpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#pragma once
#include <jni.h>
#include "jni_thread.hpp"
namespace jni
{
class Method
{
private:
const char* m_name;
const char* m_signature;
jmethodID m_index;
public:
Method(jclass klass,
char const * name,
char const * signature);
Method(jobject obj,
char const * name,
char const * signature);
void CallVoid(jobject self)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index);
};
template <typename A1>
void CallVoid(jobject self, A1 a1)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1);
}
template <typename A1, typename A2>
void CallVoid(jobject self, A1 a1, A2 a2)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2);
}
template <typename A1, typename A2, typename A3>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3);
}
template <typename A1, typename A2, typename A3, typename A4>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3, A4 a4)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3, a4);
}
template <typename A1, typename A2, typename A3, typename A4, typename A5>
void CallVoid(jobject self, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
GetCurrentThreadJNIEnv()->CallVoidMethod(self, m_index, a1, a2, a3, a4, a5);
}
jmethodID GetMethodID() const;
bool CallBoolean(jobject self);
bool CallInt(jobject self);
};
}

View file

@ -1,65 +0,0 @@
/*
* jni_thread.cpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#include "jni_thread.hpp"
#include <pthread.h>
#include "../../../../../base/logging.hpp"
namespace jni
{
JavaVM * s_jvm;
void SetCurrentJVM(JavaVM * jvm)
{
s_jvm = jvm;
}
JavaVM * GetCurrentJVM()
{
if (s_jvm == 0)
LOG(LINFO, ("no current JVM"));
return s_jvm;
}
static pthread_key_t s_jniEnvKey = 0;
JNIEnv* GetCurrentThreadJNIEnv()
{
JNIEnv* env = NULL;
if (s_jniEnvKey)
env = (JNIEnv*)pthread_getspecific(s_jniEnvKey);
else
pthread_key_create(&s_jniEnvKey, NULL);
if (!env)
{
if (!GetCurrentJVM())
{
LOG(LINFO, ("Error - could not find JVM!"));
return 0;
}
// Hmm - no env for this thread cached yet
int error = GetCurrentJVM()->AttachCurrentThread(&env, 0);
LOG(LINFO, ("AttachCurrentThread: ", error, ", ", env));
if (error || !env)
{
LOG(LINFO, ("Error - could not attach thread to JVM!"));
return 0;
}
pthread_setspecific(s_jniEnvKey, env);
}
return env;
}
}

View file

@ -1,18 +0,0 @@
/*
* jni_thread.hpp
*
* Created on: Nov 27, 2011
* Author: siarheirachytski
*/
#pragma once
#include <jni.h>
namespace jni
{
void SetCurrentJVM(JavaVM * jvm);
JavaVM * GetCurrentJVM();
JNIEnv * GetCurrentThreadJNIEnv();
}

View file

@ -1,7 +1,8 @@
#include <jni.h>
#include "../core/jni_helper.hpp"
#include "Framework.hpp"
#include "DownloadUI.hpp"
#include "../jni/jni_thread.hpp"
#include "../../../../../std/bind.hpp"
android::DownloadUI * g_downloadUI = 0;
@ -10,12 +11,15 @@ namespace android
{
DownloadUI::DownloadUI(jobject self)
{
m_self = jni::GetCurrentThreadJNIEnv()->NewGlobalRef(self);
JNIEnv * env = jni::GetEnv();
m_self = env->NewGlobalRef(self);
jclass k = jni::GetCurrentThreadJNIEnv()->GetObjectClass(m_self);
m_onChangeCountry.reset(new jni::Method(k, "onChangeCountry", "(III)V"));
m_onProgress.reset(new jni::Method(k, "onProgress", "(IIIJJ)V"));
jclass k = env->GetObjectClass(m_self);
ASSERT(k, ("Can't get java class"));
m_onChangeCountry = env->GetMethodID(k, "onChangeCountry", "(III)V");
ASSERT(m_onChangeCountry, ("Can't get onChangeCountry methodID"));
m_onProgress = env->GetMethodID(k, "onProgress", "(IIIJJ)V");
ASSERT(m_onProgress, ("Can't get onProgress methodID"));
ASSERT(!g_downloadUI, ("DownloadUI is initialized twice"));
g_downloadUI = this;
@ -23,18 +27,18 @@ namespace android
DownloadUI::~DownloadUI()
{
jni::GetCurrentThreadJNIEnv()->DeleteGlobalRef(m_self);
g_downloadUI = 0;
jni::GetEnv()->DeleteGlobalRef(m_self);
}
void DownloadUI::OnChangeCountry(storage::TIndex const & idx)
{
m_onChangeCountry->CallVoid(m_self, idx.m_group, idx.m_country, idx.m_region);
jni::GetEnv()->CallVoidMethod(m_self, m_onChangeCountry, idx.m_group, idx.m_country, idx.m_region);
}
void DownloadUI::OnProgress(storage::TIndex const & idx, pair<int64_t, int64_t> const & p)
{
m_onProgress->CallVoid(m_self, idx.m_group, idx.m_country, idx.m_region, p.first, p.second);
jni::GetEnv()->CallVoidMethod(m_self, m_onProgress, idx.m_group, idx.m_country, idx.m_region, p.first, p.second);
}
}

View file

@ -1,8 +1,8 @@
#pragma once
#include "../jni/jni_method.hpp"
#include <jni.h>
#include "../../../../../storage/storage.hpp"
#include "../../../../../std/scoped_ptr.hpp"
namespace android
{
@ -11,8 +11,8 @@ namespace android
private:
jobject m_self;
scoped_ptr<jni::Method> m_onChangeCountry;
scoped_ptr<jni::Method> m_onProgress;
jmethodID m_onChangeCountry;
jmethodID m_onProgress;
public:

View file

@ -2,9 +2,7 @@
#include "VideoTimer.hpp"
#include "../core/jni_helper.hpp"
#include "../core/jni_string.hpp"
#include "../core/render_context.hpp"
#include "../jni/jni_thread.hpp"
#include "../../../../../indexer/drawing_rules.hpp"
@ -23,8 +21,6 @@
#include "../../../../../base/logging.hpp"
#include "../../../../../base/math.hpp"
android::Framework * g_framework = 0;
namespace android
{
void Framework::CallRepaint()
@ -32,7 +28,7 @@ namespace android
//LOG(LINFO, ("Calling Repaint"));
}
Framework::Framework(JavaVM * jvm)
Framework::Framework()
: m_work(),
m_eventType(NVMultiTouchEventType(0)),
m_hasFirst(false),
@ -44,15 +40,14 @@ namespace android
ASSERT(g_framework == 0, ());
g_framework = this;
m_videoTimer = new VideoTimer(jvm, bind(&Framework::CallRepaint, this));
m_videoTimer = new VideoTimer(bind(&Framework::CallRepaint, this));
// @TODO refactor storage
m_work.Storage().ReInitCountries(false);
}
void Framework::SetEmptyModelMessage(jstring s)
void Framework::SetEmptyModelMessage(string const & emptyModelMsg)
{
std::string emptyModelMsg = jni::ToString(jni::GetCurrentThreadJNIEnv(), s);
m_work.GetInformationDisplay().setEmptyModelMessage(emptyModelMsg.c_str());
}

View file

@ -45,10 +45,10 @@ namespace android
public:
Framework(JavaVM * jvm);
Framework();
~Framework();
void SetEmptyModelMessage(jstring emptyModelMsg);
void SetEmptyModelMessage(string const & emptyModelMsg);
storage::Storage & Storage();

View file

@ -1,41 +1,17 @@
#include <jni.h>
#include "../core/logging.hpp"
#include "Framework.hpp"
#include "../platform/Platform.hpp"
#include "../../../../../platform/settings.hpp"
#include "../../../nv_event/nv_event.hpp"
#include "../jni/jni_thread.hpp"
#include "../../../../../base/logging.hpp"
JavaVM * g_jvm;
#include "../core/jni_helper.hpp"
#include "../platform/Platform.hpp"
#include "../../../nv_event/nv_event.hpp"
#include "../../../../../platform/settings.hpp"
android::Framework * g_framework = 0;
extern "C"
{
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM * jvm, void * reserved)
{
jni::InitSystemLog();
jni::InitAssertLog();
LOG(LINFO, ("logging services initialized"));
jni::SetCurrentJVM(jvm);
InitNVEvent(jvm);
g_jvm = jvm;
LOG(LDEBUG, ("JNI_OnLoad"));
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM * vm, void * reserved)
{
delete g_framework;
jni::SetCurrentJVM(0);
}
JNIEXPORT void JNICALL
Java_com_mapswithme_maps_MWMActivity_nativeInit(JNIEnv * env,
jobject thiz,
@ -60,10 +36,11 @@ extern "C"
settingsPath);
if (!g_framework)
g_framework = new android::Framework(g_jvm);
g_framework = new android::Framework();
g_framework->SetEmptyModelMessage(emptyModelMessage);
g_framework->SetEmptyModelMessage(jni::ToString(env, emptyModelMessage));
}
////////////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT void JNICALL

View file

@ -1,10 +1,3 @@
/*
* VideoTimer.cpp
*
* Created on: Nov 5, 2011
* Author: siarheirachytski
*/
#include "../core/jni_helper.hpp"
#include "VideoTimer.hpp"
#include "../../../../../base/assert.hpp"
@ -14,8 +7,8 @@ android::VideoTimer * g_timer = 0;
namespace android
{
VideoTimer::VideoTimer(JavaVM * javaVM, TFrameFn frameFn)
: m_javaVM(javaVM), ::VideoTimer(frameFn)
VideoTimer::VideoTimer(TFrameFn frameFn)
: ::VideoTimer(frameFn)
{
ASSERT(g_timer == 0, ());
g_timer = this;

View file

@ -15,13 +15,11 @@ namespace android
class VideoTimer : public ::VideoTimer
{
private:
JavaVM * m_javaVM;
jobject m_videoTimer;
public:
VideoTimer(JavaVM * jvm, TFrameFn frameFn);
VideoTimer(TFrameFn frameFn);
~VideoTimer();
void SetParentObject(jobject videoTimer);

View file

@ -1,5 +1,7 @@
#include "../../../../../platform/http_thread_callback.hpp"
#include "../core/jni_helper.hpp"
#include "../maps/DownloadUI.hpp"
class HttpThread
@ -16,7 +18,7 @@ public:
string const & pb)
{
/// should create java object here.
JNIEnv * env = jni::GetCurrentThreadJNIEnv();
JNIEnv * env = jni::GetEnv();
jclass klass = env->FindClass("com/mapswithme/maps/downloader/DownloadChunkTask");
ASSERT(klass, ("Can't find java class com/mapswithme/maps/downloader/DownloadChunkTask"));
@ -35,11 +37,8 @@ public:
~HttpThread()
{
JNIEnv * env = jni::GetCurrentThreadJNIEnv();
jclass klass = env->FindClass("com/mapswithme/maps/downloader/DownloadChunkTask");
ASSERT(klass, ("Can't find java class com/mapswithme/maps/downloader/DownloadChunkTask"));
jmethodID methodId = env->GetMethodID(klass, "cancel", "(Z)Z");
JNIEnv * env = jni::GetEnv();
jmethodID methodId = jni::GetJavaMethodID(env, m_self, "cancel", "(Z)Z");
ASSERT(methodId, ("Can't find java method 'cancel' in com/mapswithme/maps/downloader/DownloadChunkTask"));
env->CallBooleanMethod(m_self, methodId, false);
@ -73,10 +72,9 @@ extern "C"
jlong httpCallbackID, jlong beg, jbyteArray data, jlong size)
{
downloader::IHttpThreadCallback * cb = reinterpret_cast<downloader::IHttpThreadCallback*>(httpCallbackID);
JNIEnv * env0 = jni::GetCurrentThreadJNIEnv();
jbyte * buf = env0->GetByteArrayElements(data, 0);
jbyte * buf = env->GetByteArrayElements(data, 0);
cb->OnWrite(beg, buf, size);
env0->ReleaseByteArrayElements(data, buf, 0);
env->ReleaseByteArrayElements(data, buf, 0);
}
JNIEXPORT void JNICALL

View file

@ -1,22 +1,19 @@
#include <jni.h>
#include "../core/jni_helper.hpp"
#include "../../../../../base/assert.hpp"
#include "../../../../../base/logging.hpp"
#include "../../../../../std/string.hpp"
/// Defined and initialized in MWMActivity.cpp
extern JavaVM * g_jvm;
#define DEFAULT_LANG "en"
/// This function is called from native c++ code
string GetAndroidSystemLanguage()
{
JNIEnv * env = 0;
if (!g_jvm || g_jvm->AttachCurrentThread(&env, 0) || !env)
JNIEnv * env = jni::GetEnv();
if (!env)
{
LOG(LWARNING, ("Can't attach thread"));
LOG(LWARNING, ("Can't get JNIEnv"));
return DEFAULT_LANG;
}
@ -42,6 +39,6 @@ string GetAndroidSystemLanguage()
result = langUtf8;
env->ReleaseStringUTFChars(langString, langUtf8);
}
g_jvm->DetachCurrentThread();
return result;
}

View file

@ -0,0 +1,14 @@
#include "../core/jni_helper.hpp"
/// Implements bodies of base/thread.hpp functions for Android
void AndroidThreadAttachToJVM()
{
JNIEnv * env;
jni::GetJVM()->AttachCurrentThread(&env, 0);
}
void AndroidThreadDetachFromJVM()
{
jni::GetJVM()->DetachCurrentThread();
}

View file

@ -1,6 +1,6 @@
#include "Platform.hpp"
#include "../core/jni_string.hpp"
#include "../core/jni_helper.hpp"
#include "../../../../../base/logging.hpp"

View file

@ -4,7 +4,7 @@
// Email: tegradev@nvidia.com
// Web: http://developer.nvidia.com/category/zone/mobile-development
//
// Copyright 2009-2011 NVIDIA® Corporation
// Copyright 2009-2011 NVIDIA<EFBFBD> Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -32,6 +32,7 @@ static pthread_key_t s_jniEnvKey = 0;
#define MODULE "NVThread"
#include "../nv_debug/nv_debug.hpp"
#include "../com/mapswithme/core/jni_helper.hpp"
void NVThreadInit(JavaVM* vm)
{
@ -40,38 +41,40 @@ void NVThreadInit(JavaVM* vm)
JNIEnv* NVThreadGetCurrentJNIEnv()
{
JNIEnv* env = NULL;
if (s_jniEnvKey)
{
env = (JNIEnv*)pthread_getspecific(s_jniEnvKey);
}
else
{
pthread_key_create(&s_jniEnvKey, NULL);
}
return jni::GetEnv();
if (!env)
{
// do we have a VM cached?
if (!s_vm)
{
__android_log_print(ANDROID_LOG_DEBUG, MODULE, "Error - could not find JVM!");
return NULL;
}
// Hmm - no env for this thread cached yet
int error = s_vm->AttachCurrentThread(&env, NULL);
__android_log_print(ANDROID_LOG_DEBUG, MODULE, "AttachCurrentThread: %d, 0x%p", error, env);
if (error || !env)
{
__android_log_print(ANDROID_LOG_DEBUG, MODULE, "Error - could not attach thread to JVM!");
return NULL;
}
pthread_setspecific(s_jniEnvKey, env);
}
return env;
// JNIEnv* env = NULL;
// if (s_jniEnvKey)
// {
// env = (JNIEnv*)pthread_getspecific(s_jniEnvKey);
// }
// else
// {
// pthread_key_create(&s_jniEnvKey, NULL);
// }
//
// if (!env)
// {
// // do we have a VM cached?
// if (!s_vm)
// {
// __android_log_print(ANDROID_LOG_DEBUG, MODULE, "Error - could not find JVM!");
// return NULL;
// }
//
// // Hmm - no env for this thread cached yet
// int error = s_vm->AttachCurrentThread(&env, NULL);
// __android_log_print(ANDROID_LOG_DEBUG, MODULE, "AttachCurrentThread: %d, 0x%p", error, env);
// if (error || !env)
// {
// __android_log_print(ANDROID_LOG_DEBUG, MODULE, "Error - could not attach thread to JVM!");
// return NULL;
// }
//
// pthread_setspecific(s_jniEnvKey, env);
// }
//
// return env;
}
typedef struct NVThreadInitStruct
@ -80,6 +83,12 @@ typedef struct NVThreadInitStruct
void *(*m_startRoutine)(void *);
} NVThreadInitStruct;
// Implementations are in PThreadImpl.cpp
// They're used automatically if thread is created with base/thread.hpp
// @TODO: refactor and remove
void AndroidThreadAttachToJVM();
void AndroidThreadDetachFromJVM();
static void* NVThreadSpawnProc(void* arg)
{
NVThreadInitStruct* init = (NVThreadInitStruct*)arg;
@ -89,12 +98,11 @@ static void* NVThreadSpawnProc(void* arg)
free(arg);
NVThreadGetCurrentJNIEnv();
AndroidThreadAttachToJVM();
ret = start_routine(data);
if (s_vm)
s_vm->DetachCurrentThread();
AndroidThreadDetachFromJVM();
return ret;
}

View file

@ -7,6 +7,11 @@
#include "../std/windows.hpp"
#else
#include <pthread.h>
#if defined (OMIM_OS_ANDROID)
/// External implementations are in android/jni code
void AndroidThreadAttachToJVM();
void AndroidThreadDetachFromJVM();
#endif
#endif
@ -99,9 +104,19 @@ namespace threads
static void * PthreadsWrapperThreadProc(void * p)
{
#ifdef OMIM_OS_ANDROID
// Attach thread to JVM, implemented in android/jni code
AndroidThreadAttachToJVM();
#endif
IRoutine * pRoutine = reinterpret_cast<IRoutine *>(p);
pRoutine->Do();
#ifdef OMIM_OS_ANDROID
// Detach thread from JVM, implemented in android/jni code
AndroidThreadDetachFromJVM();
#endif
::pthread_exit(NULL);
return NULL;
}
@ -156,7 +171,7 @@ namespace threads
{
if (m_routine)
{
int error = m_impl->Join();
int const error = m_impl->Join();
if (0 != error)
{
ASSERT ( !"Thread join failed. See error value.", (error) );