Bug 1192077 - Move AndroidBridge JNIEnv calls to jni/Utils; r=esawin

Calls like GetJNIForThread should now belong in jni/Utils. Moving the
calls also reduce clutter in AndroidBridge.
This commit is contained in:
Jim Chen 2015-08-13 00:53:39 -04:00
parent 651217b048
commit dae9644328
5 changed files with 102 additions and 106 deletions

View File

@ -55,10 +55,8 @@ using namespace mozilla::jni;
using namespace mozilla::widget;
AndroidBridge* AndroidBridge::sBridge = nullptr;
pthread_t AndroidBridge::sJavaUiThread = -1;
static unsigned sJavaEnvThreadIndex = 0;
pthread_t AndroidBridge::sJavaUiThread;
static jobject sGlobalContext = nullptr;
static void JavaThreadDetachFunc(void *arg);
// This is a dummy class that can be used in the template for android::sp
class AndroidRefable {
@ -163,8 +161,6 @@ AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader, Object::Pa
*/
putenv("NSS_DISABLE_UNLOAD=1");
PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
MOZ_ASSERT(!sBridge);
sBridge = new AndroidBridge;
sBridge->Init(jEnv, clsLoader); // Success or crash
@ -184,10 +180,6 @@ void
AndroidBridge::Init(JNIEnv *jEnv, Object::Param clsLoader)
{
ALOG_BRIDGE("AndroidBridge::Init");
jEnv->GetJavaVM(&mJavaVM);
if (!mJavaVM) {
MOZ_CRASH(); // Nothing we can do here
}
AutoLocalJNIFrame jniFrame(jEnv);
@ -196,8 +188,6 @@ AndroidBridge::Init(JNIEnv *jEnv, Object::Param clsLoader)
jEnv, jEnv->GetObjectClass(clsLoader.Get()),
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
mJNIEnv = nullptr;
mThread = pthread_t();
mGLControllerObj = nullptr;
mOpenedGraphicsLibraries = false;
mHasNativeBitmapAccess = false;
@ -263,14 +253,10 @@ bool
AndroidBridge::SetMainThread(pthread_t thr)
{
ALOG_BRIDGE("AndroidBridge::SetMainThread");
if (thr) {
mThread = thr;
mJavaVM->GetEnv((void**) &mJNIEnv, JNI_VERSION_1_2);
return (bool) mJNIEnv;
}
mJNIEnv = nullptr;
mThread = pthread_t();
if (thr) {
return true;
}
// SetMainThread(0) is called on Gecko shutdown,
// so we should clean up the bridge here.
@ -324,29 +310,6 @@ jstring AndroidBridge::NewJavaString(AutoLocalJNIFrame* frame, const nsACString&
return NewJavaString(frame, NS_ConvertUTF8toUTF16(string));
}
extern "C" {
__attribute__ ((visibility("default")))
JNIEnv * GetJNIForThread()
{
JNIEnv *jEnv = static_cast<JNIEnv*>(PR_GetThreadPrivate(sJavaEnvThreadIndex));
if (jEnv) {
return jEnv;
}
JavaVM *jVm = mozilla::AndroidBridge::GetVM();
if (!jVm->GetEnv(reinterpret_cast<void**>(&jEnv), JNI_VERSION_1_2)) {
MOZ_ASSERT(jEnv);
return jEnv;
}
if (!jVm->AttachCurrentThread(&jEnv, nullptr)) {
MOZ_ASSERT(jEnv);
PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
return jEnv;
}
MOZ_CRASH();
return nullptr; // unreachable
}
}
void AutoGlobalWrappedJavaObject::Dispose() {
if (isNull()) {
return;
@ -1636,27 +1599,6 @@ NS_IMETHODIMP nsAndroidBridge::IsContentDocumentDisplayed(bool *aRet)
return NS_OK;
}
// DO NOT USE THIS unless you need to access JNI from
// non-main threads. This is probably not what you want.
// Questions, ask blassey or dougt.
static void
JavaThreadDetachFunc(void *arg)
{
JNIEnv *env = (JNIEnv*) arg;
MOZ_ASSERT(env, "No JNIEnv on Gecko thread");
if (!env) {
return;
}
JavaVM *vm = nullptr;
env->GetJavaVM(&vm);
MOZ_ASSERT(vm, "No JavaVM on Gecko thread");
if (!vm) {
return;
}
vm->DetachCurrentThread();
}
uint32_t
AndroidBridge::GetScreenOrientation()
{

View File

@ -141,39 +141,6 @@ public:
return sBridge;
}
static JavaVM *GetVM() {
MOZ_ASSERT(sBridge);
return sBridge->mJavaVM;
}
static JNIEnv *GetJNIEnv() {
MOZ_ASSERT(sBridge);
if (MOZ_UNLIKELY(!pthread_equal(pthread_self(), sBridge->mThread))) {
MOZ_CRASH();
}
MOZ_ASSERT(sBridge->mJNIEnv);
return sBridge->mJNIEnv;
}
static bool HasEnv() {
return sBridge && sBridge->mJNIEnv;
}
static bool ThrowException(JNIEnv *aEnv, const char *aClass,
const char *aMessage) {
return jni::ThrowException(aEnv, aClass, aMessage);
}
static bool ThrowException(JNIEnv *aEnv, const char *aMessage) {
return jni::ThrowException(aEnv, aMessage);
}
static void HandleUncaughtException(JNIEnv *aEnv) {
jni::HandleUncaughtException(aEnv);
}
// The bridge needs to be constructed via ConstructBridge first,
// and then once the Gecko main thread is spun up (Gecko side),
// SetMainThread should be called which will create the JNIEnv for
@ -351,13 +318,6 @@ protected:
static AndroidBridge* sBridge;
nsTArray<nsCOMPtr<nsIMobileMessageCallback> > mSmsRequests;
// the global JavaVM
JavaVM *mJavaVM;
// the JNIEnv for the main thread
JNIEnv *mJNIEnv;
pthread_t mThread;
widget::GeckoLayerClient::GlobalRef mLayerClient;
// the android.telephony.SmsMessage class

View File

@ -127,4 +127,11 @@ extern "C" {
JNIEnv* jsjni_GetJNIForThread() {
return GetJNIForThread();
}
// For compatibility with JNI.jsm; some addons bundle their own JNI.jsm,
// so we cannot just change the function name used in JNI.jsm.
__attribute__ ((visibility("default")))
JNIEnv* GetJNIForThread() {
return mozilla::jni::GetEnvForThread();
}
}

View File

@ -1,6 +1,8 @@
#include "Utils.h"
#include "Types.h"
#include <pthread.h>
#include "mozilla/Assertions.h"
#include "AndroidBridge.h"
@ -54,6 +56,67 @@ template<> const char TypedObject<jdoubleArray>::name[] = "[D";
template<> const char TypedObject<jobjectArray>::name[] = "[Ljava/lang/Object;";
JNIEnv* sGeckoThreadEnv;
namespace {
JavaVM* sJavaVM;
pthread_key_t sThreadEnvKey;
void UnregisterThreadEnv(void* env)
{
if (!env) {
// We were never attached.
return;
}
// The thread may have already been detached. In that case, it's still
// okay to call DetachCurrentThread(); it'll simply return an error.
// However, we must not access | env | because it may be invalid.
MOZ_ASSERT(sJavaVM);
sJavaVM->DetachCurrentThread();
}
} // namespace
void SetGeckoThreadEnv(JNIEnv* aEnv)
{
MOZ_ASSERT(aEnv);
MOZ_ASSERT(!sGeckoThreadEnv || sGeckoThreadEnv == aEnv);
if (!sGeckoThreadEnv
&& pthread_key_create(&sThreadEnvKey, UnregisterThreadEnv)) {
MOZ_CRASH("Failed to initialize required TLS");
}
sGeckoThreadEnv = aEnv;
MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, aEnv));
MOZ_ALWAYS_TRUE(!aEnv->GetJavaVM(&sJavaVM));
MOZ_ASSERT(sJavaVM);
}
JNIEnv* GetEnvForThread()
{
MOZ_ASSERT(sGeckoThreadEnv);
JNIEnv* env = static_cast<JNIEnv*>(pthread_getspecific(sThreadEnvKey));
if (env) {
return env;
}
// We don't have a saved JNIEnv, so try to get one.
// AttachCurrentThread() does the same thing as GetEnv() when a thread is
// already attached, so we don't have to call GetEnv() at all.
if (!sJavaVM->AttachCurrentThread(&env, nullptr)) {
MOZ_ASSERT(env);
MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, env));
return env;
}
MOZ_CRASH("Failed to get JNIEnv for thread");
return nullptr; // unreachable
}
bool ThrowException(JNIEnv *aEnv, const char *aClass,
const char *aMessage)
{

View File

@ -3,14 +3,38 @@
#include <jni.h>
#include "mozilla/Types.h"
/* See the comment in AndroidBridge about this function before using it */
extern "C" MOZ_EXPORT JNIEnv * GetJNIForThread();
#if defined(DEBUG) || !defined(RELEASE_BUILD)
#include "mozilla/Assertions.h"
#include "MainThreadUtils.h"
#endif
namespace mozilla {
namespace jni {
extern JNIEnv* sGeckoThreadEnv;
inline bool IsAvailable()
{
return !!sGeckoThreadEnv;
}
inline JNIEnv* GetGeckoThreadEnv()
{
#if defined(DEBUG) || !defined(RELEASE_BUILD)
if (!NS_IsMainThread()) {
MOZ_CRASH("Not on main thread");
}
if (!sGeckoThreadEnv) {
MOZ_CRASH("Don't have a JNIEnv");
}
#endif
return sGeckoThreadEnv;
}
void SetGeckoThreadEnv(JNIEnv* aEnv);
JNIEnv* GetEnvForThread();
bool ThrowException(JNIEnv *aEnv, const char *aClass,
const char *aMessage);