Bug 713803 - Rationalize JNI access accross android widget. r=blassey FIREFOX_AURORA_11_END
authorDoug Turner <dougt@dougt.org>
Sun, 29 Jan 2012 12:39:30 -0800
changeset 84353 f7a18ca15f5538901c055eb4621b95ed1cdd0fdd
parent 84352 09e15a877c8659071775bf7e2b8cbd1990799d8f
child 84354 e12d36bd9fdbccc9fa9e0a1abc7928d86dff5756
push idunknown
push userunknown
push dateunknown
reviewersblassey
bugs713803
milestone11.0a2
Bug 713803 - Rationalize JNI access accross android widget. r=blassey
dom/plugins/base/PluginPRLibrary.cpp
dom/plugins/base/android/ANPAudio.cpp
dom/plugins/base/android/ANPEvent.cpp
dom/plugins/base/android/ANPSystem.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
widget/src/android/AndroidBridge.cpp
widget/src/android/AndroidBridge.h
widget/src/android/AndroidJNI.cpp
widget/src/android/AndroidJavaWrappers.cpp
widget/src/android/nsWindow.cpp
--- a/dom/plugins/base/PluginPRLibrary.cpp
+++ b/dom/plugins/base/PluginPRLibrary.cpp
@@ -59,27 +59,30 @@ static int gNotOptimized;
 #endif
 
 namespace mozilla {
 #ifdef MOZ_WIDGET_ANDROID
 nsresult
 PluginPRLibrary::NP_Initialize(NPNetscapeFuncs* bFuncs,
 			       NPPluginFuncs* pFuncs, NPError* error)
 {
+  JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return NS_ERROR_FAILURE;
+
   if (mNP_Initialize) {
-    *error = mNP_Initialize(bFuncs, pFuncs, GetJNIForThread());
+    *error = mNP_Initialize(bFuncs, pFuncs, env);
   } else {
     NP_InitializeFunc pfNP_Initialize = (NP_InitializeFunc)
       PR_FindFunctionSymbol(mLibrary, "NP_Initialize");
     if (!pfNP_Initialize)
       return NS_ERROR_FAILURE;
-    *error = pfNP_Initialize(bFuncs, pFuncs, GetJNIForThread());
+    *error = pfNP_Initialize(bFuncs, pFuncs, env);
   }
 
-
   // Save pointers to functions that get called through PluginLibrary itself.
   mNPP_New = pFuncs->newp;
   mNPP_GetValue = pFuncs->getvalue;
   mNPP_ClearSiteData = pFuncs->clearsitedata;
   mNPP_GetSitesWithData = pFuncs->getsiteswithdata;
   return NS_OK;
 }
 #elif defined(MOZ_WIDGET_GONK)
--- a/dom/plugins/base/android/ANPAudio.cpp
+++ b/dom/plugins/base/android/ANPAudio.cpp
@@ -135,16 +135,18 @@ public:
 
   ANPAudioTrack* mTrack;
 };
 
 NS_IMETHODIMP
 AudioRunnable::Run()
 {
   JNIEnv* jenv = GetJNIForThread();
+  if (!jenv)
+    return NS_ERROR_FAILURE;
 
   if (jenv->PushLocalFrame(128)) {
     return NS_ERROR_FAILURE;
   }
 
   jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize);
   if (!bytearray) {
     LOG("AudioRunnable:: Run.  Could not create bytearray");
@@ -304,16 +306,19 @@ anp_audio_start(ANPAudioTrack* s)
   
   if (s->keepGoing) {
     // we are already playing.  Ignore.
     LOG("anp_audio_start called twice!");
     return;
   }
 
   JNIEnv *jenv = GetJNIForThread();
+  if (!jenv)
+    return;
+
   jenv->CallVoidMethod(s->output_unit, at.play);
 
   s->isStopped = false;
   s->keepGoing = true;
 
   // AudioRunnable now owns the ANPAudioTrack
   nsRefPtr<AudioRunnable> runnable = new AudioRunnable(s);
 
@@ -324,28 +329,32 @@ anp_audio_start(ANPAudioTrack* s)
 void
 anp_audio_pause(ANPAudioTrack* s)
 {
   if (s == NULL || s->output_unit == NULL) {
     return;
   }
 
   JNIEnv *jenv = GetJNIForThread();
+  if (!jenv)
+    return;
   jenv->CallVoidMethod(s->output_unit, at.pause);
 }
 
 void
 anp_audio_stop(ANPAudioTrack* s)
 {
   if (s == NULL || s->output_unit == NULL) {
     return;
   }
 
   s->isStopped = true;
   JNIEnv *jenv = GetJNIForThread();
+  if (!jenv)
+    return;
   jenv->CallVoidMethod(s->output_unit, at.stop);
 }
 
 bool
 anp_audio_isStopped(ANPAudioTrack* s)
 {
   return s->isStopped;
 }
--- a/dom/plugins/base/android/ANPEvent.cpp
+++ b/dom/plugins/base/android/ANPEvent.cpp
@@ -61,24 +61,31 @@ private:
   ANPEvent mEvent;
   NPPluginFuncs* mFuncs;
 };
 
 void
 anp_event_postEvent(NPP inst, const ANPEvent* event)
 {
   LOG("%s", __PRETTY_FUNCTION__);
+
+  JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return;
+
   if (!mozilla::AndroidBridge::Bridge()) {
     LOG("no bridge in %s!!!!", __PRETTY_FUNCTION__);
     return;
   }
+
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(inst->ndata);
   NPPluginFuncs* pluginFunctions = pinst->GetPlugin()->PluginFuncs();
-  mozilla::AndroidBridge::Bridge()->PostToJavaThread(
-    new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions), true);
+  mozilla::AndroidBridge::Bridge()->PostToJavaThread(env,
+                                                     new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions),
+                                                     true);
   LOG("returning from %s", __PRETTY_FUNCTION__);
 }
 
 
 void InitEventInterface(ANPEventInterfaceV0 *i) {
   _assert(i->inSize == sizeof(*i));
   ASSIGN(i, postEvent);
 }
--- a/dom/plugins/base/android/ANPSystem.cpp
+++ b/dom/plugins/base/android/ANPSystem.cpp
@@ -62,16 +62,19 @@ anp_system_getApplicationDataDirectory()
   return dir;
 }
 
 jclass anp_system_loadJavaClass(NPP instance, const char* className)
 {
   LOG("%s", __PRETTY_FUNCTION__);
 
   JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return nsnull;
+
   jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
   jmethodID method = env->GetStaticMethodID(cls,
                                             "loadPluginClass",
                                             "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
 
   // pass libname and classname, gotta create java strings
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2379,17 +2379,20 @@ NPError NP_CALLBACK
       LOG("get supported drawing model");
       uint32_t* bits = reinterpret_cast<uint32_t*>(result);
       *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel;
       return NPERR_NO_ERROR;
     }  
 
     case kJavaContext_ANPGetValue: {
       LOG("get context");
-      JNIEnv* env    = GetJNIForThread();
+      JNIEnv* env = GetJNIForThread();
+      if (!env)
+        return NPERR_GENERIC_ERROR;
+
       jclass cls     = env->FindClass("org/mozilla/gecko/GeckoApp");
       jfieldID field = env->GetStaticFieldID(cls, "mAppContext",
                                              "Lorg/mozilla/gecko/GeckoApp;");
       jobject ret = env->GetStaticObjectField(cls, field);
       int32_t* i  = reinterpret_cast<int32_t*>(result);
       *i = reinterpret_cast<int32_t>(ret);
       return NPERR_NO_ERROR;
     }
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -744,17 +744,25 @@ public:
   }
   nsresult Run() {
     void* surface;
     (*mPluginFunctions->getvalue)(&mNPP, kJavaSurface_ANPGetValue, &surface);
     mInstance->SetJavaSurface(surface);
     return NS_OK;
   }
   void RequestSurface() {
-    mozilla::AndroidBridge::Bridge()->PostToJavaThread(this);
+    JNIEnv* env = GetJNIForThread();
+    if (!env)
+      return;
+
+    if (!mozilla::AndroidBridge::Bridge()) {
+      PLUGIN_LOG(PLUGIN_LOG_BASIC, ("nsNPAPIPluginInstance null AndroidBridge"));
+      return;
+    }
+    mozilla::AndroidBridge::Bridge()->PostToJavaThread(env, this);
   }
 private:
   nsNPAPIPluginInstance* mInstance;
   NPP_t mNPP;
   NPPluginFuncs* mPluginFunctions;
 };
 
 
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1740,41 +1740,42 @@ bool nsPluginInstanceOwner::AddPluginVie
     mPluginViewAdded = true;
   }
 
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
-  AndroidBridge::AutoLocalJNIFrame frame(1);
-
-  if (mInstance && mObjectFrame && mPluginViewAdded) {
-    mPluginViewAdded = false;
-
-    void* surface = mInstance->GetJavaSurface();
-    if (surface) {
-      JNIEnv* env = GetJNIForThread();
-      if (env) {
-        jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
-        jmethodID method = env->GetStaticMethodID(cls,
-                                                  "removePluginView",
-                                                  "(Landroid/view/View;)V");
-        env->CallStaticVoidMethod(cls, method, surface);
-
-        {
-          ANPEvent event;
-          event.inSize = sizeof(ANPEvent);
-          event.eventType = kLifecycle_ANPEventType;
-          event.data.lifecycle.action = kOffScreen_ANPLifecycleAction;
-          mInstance->HandleEvent(&event, nsnull);
-        }
-      }
-    }
-  }
+  if (!mInstance || !mObjectFrame | !mPluginViewAdded)
+    return;
+
+  mPluginViewAdded = false;
+
+  void* surface = mInstance->GetJavaSurface();
+  if (!surface)
+    return;
+
+  JNIEnv* env = GetJNIForThread();
+  if (!env)
+    return;
+
+  AndroidBridge::AutoLocalJNIFrame frame(env, 1);
+
+  jclass cls = env->FindClass("org/mozilla/gecko/GeckoAppShell");
+  jmethodID method = env->GetStaticMethodID(cls,
+                                            "removePluginView",
+                                            "(Landroid/view/View;)V");
+  env->CallStaticVoidMethod(cls, method, surface);
+
+  ANPEvent event;
+  event.inSize = sizeof(ANPEvent);
+  event.eventType = kLifecycle_ANPEventType;
+  event.data.lifecycle.action = kOffScreen_ANPLifecycleAction;
+  mInstance->HandleEvent(&event, nsnull);
 }
 #endif
 
 nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
 {
 #ifdef MOZ_WIDGET_ANDROID
   {
     ANPEvent event;
--- a/widget/src/android/AndroidBridge.cpp
+++ b/widget/src/android/AndroidBridge.cpp
@@ -35,51 +35,40 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <android/log.h>
 #include <dlfcn.h>
 
 #include "mozilla/Hal.h"
 #include "nsXULAppAPI.h"
-#include <pthread.h>
 #include <prthread.h>
 #include "nsXPCOMStrings.h"
 
 #include "AndroidBridge.h"
 #include "nsAppShell.h"
 #include "nsOSHelperAppService.h"
 #include "nsWindow.h"
 #include "mozilla/Preferences.h"
 #include "nsThreadUtils.h"
+#include "nsIThreadManager.h"
 
 #ifdef DEBUG
 #define ALOG_BRIDGE(args...) ALOG(args)
 #else
 #define ALOG_BRIDGE(args...)
 #endif
 
 #define IME_FULLSCREEN_PREF "widget.ime.android.landscape_fullscreen"
 #define IME_FULLSCREEN_THRESHOLD_PREF "widget.ime.android.fullscreen_threshold"
 
 using namespace mozilla;
 
-static PRUintn sJavaEnvThreadIndex = 0;
-
 AndroidBridge *AndroidBridge::sBridge = 0;
 
-static void
-JavaThreadDetachFunc(void *arg)
-{
-    JNIEnv *env = (JNIEnv*) arg;
-    JavaVM *vm = NULL;
-    env->GetJavaVM(&vm);
-    vm->DetachCurrentThread();
-}
-
 AndroidBridge *
 AndroidBridge::ConstructBridge(JNIEnv *jEnv,
                                jclass jGeckoAppShellClass)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
@@ -87,19 +76,16 @@ AndroidBridge::ConstructBridge(JNIEnv *j
      */
     putenv("NSS_DISABLE_UNLOAD=1"); 
 
     sBridge = new AndroidBridge();
     if (!sBridge->Init(jEnv, jGeckoAppShellClass)) {
         delete sBridge;
         sBridge = 0;
     }
-
-    PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
-
     return sBridge;
 }
 
 bool
 AndroidBridge::Init(JNIEnv *jEnv,
                     jclass jGeckoAppShellClass)
 {
     ALOG_BRIDGE("AndroidBridge::Init");
@@ -180,114 +166,64 @@ AndroidBridge::Init(JNIEnv *jEnv,
 
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return true;
 }
 
-JNIEnv *
-AndroidBridge::AttachThread(bool asDaemon)
-{
-    // If we already have a env, return it
-    JNIEnv *jEnv = NULL;
-    mJavaVM->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
-    if (jEnv)
-        return jEnv;
-
-    ALOG_BRIDGE("AndroidBridge::AttachThread");
-    jEnv = (JNIEnv*) PR_GetThreadPrivate(sJavaEnvThreadIndex);
-    if (jEnv)
-        return jEnv;
-
-    JavaVMAttachArgs args = {
-        JNI_VERSION_1_2,
-        "GeckoThread",
-        NULL
-    };
-
-    jint res = 0;
-
-    if (asDaemon) {
-        res = mJavaVM->AttachCurrentThreadAsDaemon(&jEnv, &args);
-    } else {
-        res = mJavaVM->AttachCurrentThread(&jEnv, &args);
-    }
-
-    if (res != 0) {
-        ALOG_BRIDGE("AttachCurrentThread failed!");
-        return nsnull;
-    }
-
-    PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
-
-    PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
-
-    return jEnv;
-}
-
 bool
 AndroidBridge::SetMainThread(void *thr)
 {
     ALOG_BRIDGE("AndroidBridge::SetMainThread");
     if (thr) {
-        mJNIEnv = AttachThread(false);
-        if (!mJNIEnv)
-            return false;
-
         mThread = thr;
-    } else {
-        mJNIEnv = nsnull;
-        mThread = nsnull;
+        mJavaVM->GetEnv((void**) &mJNIEnv, JNI_VERSION_1_2);
+        return (bool) mJNIEnv;
     }
 
+    mJNIEnv = nsnull;
+    mThread = nsnull;
     return true;
 }
 
 void
-AndroidBridge::EnsureJNIThread()
-{
-    JNIEnv *env;
-    if (mJavaVM->AttachCurrentThread(&env, NULL) != 0) {
-        ALOG_BRIDGE("EnsureJNIThread: test Attach failed!");
-        return;
-    }
-
-    if ((void*)pthread_self() != mThread) {
-        ALOG_BRIDGE("###!!!!!!! Something's grabbing the JNIEnv from the wrong thread! (thr %p should be %p)",
-             (void*)pthread_self(), (void*)mThread);
-    }
-}
-
-void
 AndroidBridge::NotifyIME(int aType, int aState)
 {
     ALOG_BRIDGE("AndroidBridge::NotifyIME");
-    if (sBridge)
-        JNI()->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, 
-                                    sBridge->jNotifyIME,  aType, aState);
+
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, 
+                              sBridge->jNotifyIME,  aType, aState);
 }
 
 void
 AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
                                 const nsAString& aActionHint)
 {
     ALOG_BRIDGE("AndroidBridge::NotifyIMEEnabled");
     if (!sBridge)
         return;
 
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
     nsPromiseFlatString typeHint(aTypeHint);
     nsPromiseFlatString actionHint(aActionHint);
 
     jvalue args[4];
-    AutoLocalJNIFrame jniFrame(1);
+    AutoLocalJNIFrame jniFrame(env, 1);
     args[0].i = aState;
-    args[1].l = JNI()->NewString(typeHint.get(), typeHint.Length());
-    args[2].l = JNI()->NewString(actionHint.get(), actionHint.Length());
+    args[1].l = env->NewString(typeHint.get(), typeHint.Length());
+    args[2].l = env->NewString(actionHint.get(), actionHint.Length());
     args[3].z = false;
 
     PRInt32 landscapeFS;
     if (NS_SUCCEEDED(Preferences::GetInt(IME_FULLSCREEN_PREF, &landscapeFS))) {
         if (landscapeFS == 1) {
             args[3].z = true;
         } else if (landscapeFS == -1){
             if (NS_SUCCEEDED(
@@ -299,86 +235,120 @@ AndroidBridge::NotifyIMEEnabled(int aSta
                     landscapeFS * Bridge()->GetDPI()) {
                     args[3].z = true;
                 }
             }
 
         }
     }
 
-    JNI()->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
+    env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
                                  sBridge->jNotifyIMEEnabled, args);
 }
 
 void
 AndroidBridge::NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen,
                                int aStart, int aEnd, int aNewEnd)
 {
     ALOG_BRIDGE("AndroidBridge::NotifyIMEChange");
     if (!sBridge) {
         return;
     }
 
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
     jvalue args[4];
-    AutoLocalJNIFrame jniFrame(1);
-    args[0].l = JNI()->NewString(aText, aTextLen);
+    AutoLocalJNIFrame jniFrame(env, 1);
+    args[0].l = env->NewString(aText, aTextLen);
     args[1].i = aStart;
     args[2].i = aEnd;
     args[3].i = aNewEnd;
-    JNI()->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
+    env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
                                      sBridge->jNotifyIMEChange, args);
 }
 
 void
 AndroidBridge::AcknowledgeEventSync()
 {
     ALOG_BRIDGE("AndroidBridge::AcknowledgeEventSync");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
 }
 
 void
 AndroidBridge::EnableDeviceMotion(bool aEnable)
 {
     ALOG_BRIDGE("AndroidBridge::EnableDeviceMotion");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableDeviceMotion, aEnable);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableDeviceMotion, aEnable);
 }
 
 void
 AndroidBridge::EnableLocation(bool aEnable)
 {
     ALOG_BRIDGE("AndroidBridge::EnableLocation");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+    
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable);
 }
 
 void
 AndroidBridge::ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen,
                                     int aSelStart, int aSelLen)
 {
     ALOG_BRIDGE("AndroidBridge::ReturnIMEQueryResult");
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
     jvalue args[3];
-    AutoLocalJNIFrame jniFrame(1);
-    args[0].l = mJNIEnv->NewString(aResult, aLen);
+    AutoLocalJNIFrame jniFrame(env, 1);
+    args[0].l = env->NewString(aResult, aLen);
     args[1].i = aSelStart;
     args[2].i = aSelLen;
-    mJNIEnv->CallStaticVoidMethodA(mGeckoAppShellClass,
-                                   jReturnIMEQueryResult, args);
+    env->CallStaticVoidMethodA(mGeckoAppShellClass,
+                               jReturnIMEQueryResult, args);
 }
 
 void
 AndroidBridge::ScheduleRestart()
 {
     ALOG_BRIDGE("scheduling reboot");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
 }
 
 void
 AndroidBridge::NotifyXreExit()
 {
     ALOG_BRIDGE("xre exiting");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
 }
 
 static void 
 getHandlersFromStringArray(JNIEnv *aJNIEnv, jobjectArray jArr, jsize aLen,
                            nsIMutableArray *aHandlersArray,
                            nsIHandlerApp **aDefaultApp,
                            const nsAString& aAction = EmptyString(),
                            const nsACString& aMimeType = EmptyCString())
@@ -406,294 +376,383 @@ getHandlersFromStringArray(JNIEnv *aJNIE
 bool
 AndroidBridge::GetHandlersForMimeType(const char *aMimeType,
                                       nsIMutableArray *aHandlersArray,
                                       nsIHandlerApp **aDefaultApp,
                                       const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env); 
     NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
     jstring jstrMimeType =
-        mJNIEnv->NewString(wMimeType.get(), wMimeType.Length());
+        env->NewString(wMimeType.get(), wMimeType.Length());
 
-    jstring jstrAction = mJNIEnv->NewString(nsPromiseFlatString(aAction).get(),
+    jstring jstrAction = env->NewString(nsPromiseFlatString(aAction).get(),
                                             aAction.Length());
 
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass,
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass,
                                                   jGetHandlersForMimeType,
                                                   jstrMimeType, jstrAction);
     jobjectArray arr = static_cast<jobjectArray>(obj);
     if (!arr)
         return false;
 
-    jsize len = mJNIEnv->GetArrayLength(arr);
+    jsize len = env->GetArrayLength(arr);
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(mJNIEnv, arr, len, aHandlersArray, 
+    getHandlersFromStringArray(env, arr, len, aHandlersArray, 
                                aDefaultApp, aAction,
                                nsDependentCString(aMimeType));
     return true;
 }
 
 bool
 AndroidBridge::GetHandlersForURL(const char *aURL,
                                  nsIMutableArray* aHandlersArray,
                                  nsIHandlerApp **aDefaultApp,
                                  const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env); 
     NS_ConvertUTF8toUTF16 wScheme(aURL);
-    jstring jstrScheme = mJNIEnv->NewString(wScheme.get(), wScheme.Length());
-    jstring jstrAction = mJNIEnv->NewString(nsPromiseFlatString(aAction).get(),
+    jstring jstrScheme = env->NewString(wScheme.get(), wScheme.Length());
+    jstring jstrAction = env->NewString(nsPromiseFlatString(aAction).get(),
                                             aAction.Length());
 
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass,
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass,
                                                   jGetHandlersForURL,
                                                   jstrScheme, jstrAction);
     jobjectArray arr = static_cast<jobjectArray>(obj);
     if (!arr)
         return false;
 
-    jsize len = mJNIEnv->GetArrayLength(arr);
+    jsize len = env->GetArrayLength(arr);
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(mJNIEnv, arr, len, aHandlersArray, 
+    getHandlersFromStringArray(env, arr, len, aHandlersArray, 
                                aDefaultApp, aAction);
     return true;
 }
 
 bool
 AndroidBridge::OpenUriExternal(const nsACString& aUriSpec, const nsACString& aMimeType,
                                const nsAString& aPackageName, const nsAString& aClassName,
                                const nsAString& aAction, const nsAString& aTitle)
 {
     ALOG_BRIDGE("AndroidBridge::OpenUriExternal");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env); 
     NS_ConvertUTF8toUTF16 wUriSpec(aUriSpec);
     NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
 
-    jstring jstrUri = mJNIEnv->NewString(wUriSpec.get(), wUriSpec.Length());
-    jstring jstrType = mJNIEnv->NewString(wMimeType.get(), wMimeType.Length());
+    jstring jstrUri = env->NewString(wUriSpec.get(), wUriSpec.Length());
+    jstring jstrType = env->NewString(wMimeType.get(), wMimeType.Length());
 
-    jstring jstrPackage = mJNIEnv->NewString(nsPromiseFlatString(aPackageName).get(),
+    jstring jstrPackage = env->NewString(nsPromiseFlatString(aPackageName).get(),
                                              aPackageName.Length());
-    jstring jstrClass = mJNIEnv->NewString(nsPromiseFlatString(aClassName).get(),
+    jstring jstrClass = env->NewString(nsPromiseFlatString(aClassName).get(),
                                            aClassName.Length());
-    jstring jstrAction = mJNIEnv->NewString(nsPromiseFlatString(aAction).get(),
+    jstring jstrAction = env->NewString(nsPromiseFlatString(aAction).get(),
                                             aAction.Length());
-    jstring jstrTitle = mJNIEnv->NewString(nsPromiseFlatString(aTitle).get(),
+    jstring jstrTitle = env->NewString(nsPromiseFlatString(aTitle).get(),
                                            aTitle.Length());
 
-    return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass,
+    return env->CallStaticBooleanMethod(mGeckoAppShellClass,
                                             jOpenUriExternal,
                                             jstrUri, jstrType, jstrPackage, 
                                             jstrClass, jstrAction, jstrTitle);
 }
 
 void
 AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
 {
     ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
     NS_ConvertUTF8toUTF16 wFileExt(aFileExt);
-    jstring jstrExt = mJNIEnv->NewString(wFileExt.get(), wFileExt.Length());
+    jstring jstrExt = env->NewString(wFileExt.get(), wFileExt.Length());
     jstring jstrType =  static_cast<jstring>(
-        mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass,
+        env->CallStaticObjectMethod(mGeckoAppShellClass,
                                         jGetMimeTypeFromExtensions,
                                         jstrExt));
     nsJNIString jniStr(jstrType);
     aMimeType.Assign(NS_ConvertUTF16toUTF8(jniStr.get()));
 }
 
 void
 AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
 {
     ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
     NS_ConvertUTF8toUTF16 wMimeType(aMimeType);
-    jstring jstrType = mJNIEnv->NewString(wMimeType.get(), wMimeType.Length());
+    jstring jstrType = env->NewString(wMimeType.get(), wMimeType.Length());
     jstring jstrExt = static_cast<jstring>(
-        mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass,
+        env->CallStaticObjectMethod(mGeckoAppShellClass,
                                         jGetExtensionFromMimeType,
                                         jstrType));
     nsJNIString jniStr(jstrExt);
     aFileExt.Assign(NS_ConvertUTF16toUTF8(jniStr.get()));
 }
 
 void
 AndroidBridge::MoveTaskToBack()
 {
     ALOG_BRIDGE("AndroidBridge::MoveTaskToBack");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack);
 }
 
 bool
 AndroidBridge::GetClipboardText(nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::GetClipboardText");
 
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
     jstring jstrType =  
-        static_cast<jstring>(mJNIEnv->
+        static_cast<jstring>(env->
                              CallStaticObjectMethod(mGeckoAppShellClass,
                                                     jGetClipboardText));
     if (!jstrType)
         return false;
     nsJNIString jniStr(jstrType);
     aText.Assign(jniStr);
     return true;
 }
 
 void
 AndroidBridge::SetClipboardText(const nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::SetClipboardText");
-    AutoLocalJNIFrame jniFrame;
-    jstring jstr = mJNIEnv->NewString(nsPromiseFlatString(aText).get(),
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+    jstring jstr = env->NewString(nsPromiseFlatString(aText).get(),
                                       aText.Length());
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, jstr);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, jstr);
 }
 
 bool
 AndroidBridge::ClipboardHasText()
 {
     ALOG_BRIDGE("AndroidBridge::ClipboardHasText");
 
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
     jstring jstrType =  
-        static_cast<jstring>(mJNIEnv->
+        static_cast<jstring>(env->
                              CallStaticObjectMethod(mGeckoAppShellClass,
                                                     jGetClipboardText));
     if (!jstrType)
         return false;
     return true;
 }
 
 void
 AndroidBridge::EmptyClipboard()
 {
     ALOG_BRIDGE("AndroidBridge::EmptyClipboard");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, nsnull);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, nsnull);
 }
 
 void
 AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
                                      const nsAString& aAlertTitle,
                                      const nsAString& aAlertText,
                                      const nsAString& aAlertCookie,
                                      nsIObserver *aAlertListener,
                                      const nsAString& aAlertName)
 {
     ALOG_BRIDGE("ShowAlertNotification");
-    AutoLocalJNIFrame jniFrame;
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     if (nsAppShell::gAppShell && aAlertListener)
         nsAppShell::gAppShell->AddObserver(aAlertName, aAlertListener);
 
     jvalue args[5];
-    args[0].l = mJNIEnv->NewString(nsPromiseFlatString(aImageUrl).get(), aImageUrl.Length());
-    args[1].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertTitle).get(), aAlertTitle.Length());
-    args[2].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
-    args[3].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertCookie).get(), aAlertCookie.Length());
-    args[4].l = mJNIEnv->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
-    mJNIEnv->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotification, args);
+    args[0].l = env->NewString(nsPromiseFlatString(aImageUrl).get(), aImageUrl.Length());
+    args[1].l = env->NewString(nsPromiseFlatString(aAlertTitle).get(), aAlertTitle.Length());
+    args[2].l = env->NewString(nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
+    args[3].l = env->NewString(nsPromiseFlatString(aAlertCookie).get(), aAlertCookie.Length());
+    args[4].l = env->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
+    env->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotification, args);
 }
 
 void
 AndroidBridge::AlertsProgressListener_OnProgress(const nsAString& aAlertName,
                                                  PRInt64 aProgress,
                                                  PRInt64 aProgressMax,
                                                  const nsAString& aAlertText)
 {
     ALOG_BRIDGE("AlertsProgressListener_OnProgress");
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
 
-    jstring jstrName = mJNIEnv->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
-    jstring jstrText = mJNIEnv->NewString(nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnProgress,
+    AutoLocalJNIFrame jniFrame(env); 
+
+    jstring jstrName = env->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
+    jstring jstrText = env->NewString(nsPromiseFlatString(aAlertText).get(), aAlertText.Length());
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnProgress,
                                   jstrName, aProgress, aProgressMax, jstrText);
 }
 
 void
 AndroidBridge::AlertsProgressListener_OnCancel(const nsAString& aAlertName)
 {
     ALOG_BRIDGE("AlertsProgressListener_OnCancel");
-    AutoLocalJNIFrame jniFrame;
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
 
-    jstring jstrName = mJNIEnv->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnCancel, jstrName);
+    AutoLocalJNIFrame jniFrame(env); 
+
+    jstring jstrName = env->NewString(nsPromiseFlatString(aAlertName).get(), aAlertName.Length());
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jAlertsProgressListener_OnCancel, jstrName);
 }
 
-
 int
 AndroidBridge::GetDPI()
 {
     ALOG_BRIDGE("AndroidBridge::GetDPI");
-    return (int) mJNIEnv->CallStaticIntMethod(mGeckoAppShellClass, jGetDpi);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return 72; // what is a better value.  If we don't have a env here, we are hosed.
+
+    return (int) env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpi);
 }
 
 void
 AndroidBridge::ShowFilePicker(nsAString& aFilePath, nsAString& aFilters)
 {
     ALOG_BRIDGE("AndroidBridge::ShowFilePicker");
 
-    AutoLocalJNIFrame jniFrame;
-    jstring jstrFilers = mJNIEnv->NewString(nsPromiseFlatString(aFilters).get(),
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+    jstring jstrFilers = env->NewString(nsPromiseFlatString(aFilters).get(),
                                             aFilters.Length());
-    jstring jstr =  static_cast<jstring>(mJNIEnv->CallStaticObjectMethod(
+    jstring jstr =  static_cast<jstring>(env->CallStaticObjectMethod(
                                              mGeckoAppShellClass,
                                              jShowFilePicker, jstrFilers));
     aFilePath.Assign(nsJNIString(jstr));
 }
 
 void
 AndroidBridge::SetFullScreen(bool aFullScreen)
 {
     ALOG_BRIDGE("AndroidBridge::SetFullScreen");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, aFullScreen);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, aFullScreen);
 }
 
 void
 AndroidBridge::HideProgressDialogOnce()
 {
     static bool once = false;
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
     if (!once) {
         ALOG_BRIDGE("AndroidBridge::HideProgressDialogOnce");
-        mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
+        env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
         once = true;
     }
 }
 
 bool
 AndroidBridge::GetAccessibilityEnabled()
 {
     ALOG_BRIDGE("AndroidBridge::GetAccessibilityEnabled");
-    return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jGetAccessibilityEnabled);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    return env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetAccessibilityEnabled);
 }
 
 void
 AndroidBridge::PerformHapticFeedback(bool aIsLongPress)
 {
     ALOG_BRIDGE("AndroidBridge::PerformHapticFeedback");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass,
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass,
                                     jPerformHapticFeedback, aIsLongPress);
 }
 
 void
 AndroidBridge::Vibrate(const nsTArray<PRUint32>& aPattern)
 {
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
     AutoLocalJNIFrame frame;
 
     ALOG_BRIDGE("AndroidBridge::Vibrate");
 
     PRUint32 len = aPattern.Length();
     if (!len) {
         ALOG_BRIDGE("  invalid 0-length array");
         return;
@@ -702,148 +761,180 @@ AndroidBridge::Vibrate(const nsTArray<PR
     // It's clear if this worth special-casing, but it creates less
     // java junk, so dodges the GC.
     if (len == 1) {
         jlong d = aPattern[0];
         if (d < 0) {
             ALOG_BRIDGE("  invalid vibration duration < 0");
             return;
         }
-        mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jVibrate1, d);
+        env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrate1, d);
        return;
     }
 
     // First element of the array vibrate() expects is how long to wait
     // *before* vibrating.  For us, this is always 0.
 
-    jlongArray array = mJNIEnv->NewLongArray(len + 1);
+    jlongArray array = env->NewLongArray(len + 1);
     if (!array) {
         ALOG_BRIDGE("  failed to allocate array");
         return;
     }
 
-    jlong* elts = mJNIEnv->GetLongArrayElements(array, nsnull);
+    jlong* elts = env->GetLongArrayElements(array, nsnull);
     elts[0] = 0;
     for (PRUint32 i = 0; i < aPattern.Length(); ++i) {
         jlong d = aPattern[i];
         if (d < 0) {
             ALOG_BRIDGE("  invalid vibration duration < 0");
-            mJNIEnv->ReleaseLongArrayElements(array, elts, JNI_ABORT);
+            env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
             return;
         }
         elts[i + 1] = d;
     }
-    mJNIEnv->ReleaseLongArrayElements(array, elts, 0);
+    env->ReleaseLongArrayElements(array, elts, 0);
 
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jVibrateA,
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrateA,
                                   array, -1/*don't repeat*/);
     // GC owns |array| now?
 }
 
 void
 AndroidBridge::CancelVibrate()
 {
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate);
 }
 
 bool
 AndroidBridge::IsNetworkLinkUp()
 {
     ALOG_BRIDGE("AndroidBridge::IsNetworkLinkUp");
-    return !!mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    return !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp);
 }
 
 bool
 AndroidBridge::IsNetworkLinkKnown()
 {
     ALOG_BRIDGE("AndroidBridge::IsNetworkLinkKnown");
-    return !!mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    return !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown);
 }
 
 void
 AndroidBridge::SetSelectedLocale(const nsAString& aLocale)
 {
     ALOG_BRIDGE("AndroidBridge::SetSelectedLocale");
-    AutoLocalJNIFrame jniFrame;
-    jstring jLocale = GetJNIForThread()->NewString(PromiseFlatString(aLocale).get(), aLocale.Length());
-    GetJNIForThread()->CallStaticVoidMethod(mGeckoAppShellClass, jSetSelectedLocale, jLocale);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+    jstring jLocale = env->NewString(PromiseFlatString(aLocale).get(), aLocale.Length());
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetSelectedLocale, jLocale);
 }
 
 void
 AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
 {
     ALOG_BRIDGE("AndroidBridge::GetSystemColors");
 
     NS_ASSERTION(aColors != nsnull, "AndroidBridge::GetSystemColors: aColors is null!");
     if (!aColors)
         return;
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
 
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColors);
+    AutoLocalJNIFrame jniFrame(env); 
+
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColors);
     jintArray arr = static_cast<jintArray>(obj);
     if (!arr)
         return;
 
-    jsize len = mJNIEnv->GetArrayLength(arr);
-    jint *elements = mJNIEnv->GetIntArrayElements(arr, 0);
+    jsize len = env->GetArrayLength(arr);
+    jint *elements = env->GetIntArrayElements(arr, 0);
 
     PRUint32 colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
     if (len < colorsCount)
         colorsCount = len;
 
     // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
     nscolor *colors = (nscolor*)aColors;
 
     for (PRUint32 i = 0; i < colorsCount; i++) {
         PRUint32 androidColor = static_cast<PRUint32>(elements[i]);
         PRUint8 r = (androidColor & 0x00ff0000) >> 16;
         PRUint8 b = (androidColor & 0x000000ff);
         colors[i] = androidColor & 0xff00ff00 | b << 16 | r;
     }
 
-    mJNIEnv->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr, elements, 0);
 }
 
 void
 AndroidBridge::GetIconForExtension(const nsACString& aFileExt, PRUint32 aIconSize, PRUint8 * const aBuf)
 {
     ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
     NS_ASSERTION(aBuf != nsnull, "AndroidBridge::GetIconForExtension: aBuf is null!");
     if (!aBuf)
         return;
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     nsString fileExt;
     CopyUTF8toUTF16(aFileExt, fileExt);
-    jstring jstrFileExt = mJNIEnv->NewString(nsPromiseFlatString(fileExt).get(), fileExt.Length());
+    jstring jstrFileExt = env->NewString(nsPromiseFlatString(fileExt).get(), fileExt.Length());
     
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtension, jstrFileExt, aIconSize);
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtension, jstrFileExt, aIconSize);
     jbyteArray arr = static_cast<jbyteArray>(obj);
     NS_ASSERTION(arr != nsnull, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
     if (!arr)
         return;
 
-    jsize len = mJNIEnv->GetArrayLength(arr);
-    jbyte *elements = mJNIEnv->GetByteArrayElements(arr, 0);
+    jsize len = env->GetArrayLength(arr);
+    jbyte *elements = env->GetByteArrayElements(arr, 0);
 
     PRUint32 bufSize = aIconSize * aIconSize * 4;
     NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
     if (len == bufSize)
         memcpy(aBuf, elements, bufSize);
 
-    mJNIEnv->ReleaseByteArrayElements(arr, elements, 0);
+    env->ReleaseByteArrayElements(arr, elements, 0);
 }
 
 bool
 AndroidBridge::GetShowPasswordSetting()
 {
     ALOG_BRIDGE("AndroidBridge::GetShowPasswordSetting");
-    return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    return env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting);
 }
 
 void
 AndroidBridge::SetSurfaceView(jobject obj)
 {
     mSurfaceView.Init(obj);
 }
 
@@ -852,24 +943,34 @@ AndroidBridge::SetSoftwareLayerClient(jo
 {
     mSoftwareLayerClient.Init(obj);
 }
 
 void
 AndroidBridge::ShowInputMethodPicker()
 {
     ALOG_BRIDGE("AndroidBridge::ShowInputMethodPicker");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker);
 }
 
 void *
 AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView &sview)
 {
     ALOG_BRIDGE("AndroidBridge::CallEglCreateWindowSurface");
-    AutoLocalJNIFrame jniFrame;
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return NULL;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     /*
      * This is basically:
      *
      *    s = EGLContext.getEGL().eglCreateWindowSurface(new EGLDisplayImpl(dpy),
      *                                                   new EGLConfigImpl(config),
      *                                                   view.getHolder(), null);
      *    return s.mEGLSurface;
@@ -877,172 +978,160 @@ AndroidBridge::CallEglCreateWindowSurfac
      * We can't do it from java, because the EGLConfigImpl constructor is private.
      */
 
     jobject surfaceHolder = sview.GetSurfaceHolder();
     if (!surfaceHolder)
         return nsnull;
 
     // grab some fields and methods we'll need
-    jmethodID constructConfig = mJNIEnv->GetMethodID(jEGLConfigImplClass, "<init>", "(I)V");
-    jmethodID constructDisplay = mJNIEnv->GetMethodID(jEGLDisplayImplClass, "<init>", "(I)V");
+    jmethodID constructConfig = env->GetMethodID(jEGLConfigImplClass, "<init>", "(I)V");
+    jmethodID constructDisplay = env->GetMethodID(jEGLDisplayImplClass, "<init>", "(I)V");
 
-    jmethodID getEgl = mJNIEnv->GetStaticMethodID(jEGLContextClass, "getEGL", "()Ljavax/microedition/khronos/egl/EGL;");
-    jmethodID createWindowSurface = mJNIEnv->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;");
+    jmethodID getEgl = env->GetStaticMethodID(jEGLContextClass, "getEGL", "()Ljavax/microedition/khronos/egl/EGL;");
+    jmethodID createWindowSurface = env->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;");
 
-    jobject egl = mJNIEnv->CallStaticObjectMethod(jEGLContextClass, getEgl);
+    jobject egl = env->CallStaticObjectMethod(jEGLContextClass, getEgl);
 
-    jobject jdpy = mJNIEnv->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy);
-    jobject jconf = mJNIEnv->NewObject(jEGLConfigImplClass, constructConfig, (int) config);
+    jobject jdpy = env->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy);
+    jobject jconf = env->NewObject(jEGLConfigImplClass, constructConfig, (int) config);
 
     // make the call
-    jobject surf = mJNIEnv->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL);
+    jobject surf = env->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL);
     if (!surf)
         return nsnull;
 
-    jfieldID sfield = mJNIEnv->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I");
+    jfieldID sfield = env->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I");
 
-    jint realSurface = mJNIEnv->GetIntField(surf, sfield);
+    jint realSurface = env->GetIntField(surf, sfield);
 
     return (void*) realSurface;
 }
 
 bool
 AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, PRInt32* aInt)
 {
     ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
-    AutoLocalJNIFrame jniFrame(3);
-    jclass cls = mJNIEnv->FindClass(className);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env, 3);
+    jclass cls = env->FindClass(className);
     if (!cls)
         return false;
 
-    jfieldID field = mJNIEnv->GetStaticFieldID(cls, fieldName, "I");
+    jfieldID field = env->GetStaticFieldID(cls, fieldName, "I");
     if (!field)
         return false;
 
-    *aInt = static_cast<PRInt32>(mJNIEnv->GetStaticIntField(cls, field));
+    *aInt = static_cast<PRInt32>(env->GetStaticIntField(cls, field));
 
     return true;
 }
 
 bool
 AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result)
 {
     ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
 
-    AutoLocalJNIFrame jniFrame(3);
-    jclass cls = mJNIEnv->FindClass(className);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env, 3);
+    jclass cls = env->FindClass(className);
     if (!cls)
         return false;
 
-    jfieldID field = mJNIEnv->GetStaticFieldID(cls, fieldName, "Ljava/lang/String;");
+    jfieldID field = env->GetStaticFieldID(cls, fieldName, "Ljava/lang/String;");
     if (!field)
         return false;
 
-    jstring jstr = (jstring) mJNIEnv->GetStaticObjectField(cls, field);
+    jstring jstr = (jstring) env->GetStaticObjectField(cls, field);
     if (!jstr)
         return false;
 
     result.Assign(nsJNIString(jstr));
     return true;
 }
 
 void
 AndroidBridge::SetKeepScreenOn(bool on)
 {
     ALOG_BRIDGE("AndroidBridge::SetKeepScreenOn");
-    JNI()->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
-                                sBridge->jSetKeepScreenOn, on);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass,
+                              sBridge->jSetKeepScreenOn, on);
 }
 
 // Available for places elsewhere in the code to link to.
 bool
 mozilla_AndroidBridge_SetMainThread(void *thr)
 {
     return AndroidBridge::Bridge()->SetMainThread(thr);
 }
 
-JavaVM *
-mozilla_AndroidBridge_GetJavaVM()
-{
-    return AndroidBridge::Bridge()->VM();
-}
-
-JNIEnv *
-mozilla_AndroidBridge_AttachThread(bool asDaemon)
-{
-    return AndroidBridge::Bridge()->AttachThread(asDaemon);
-}
-
-extern "C" {
-    __attribute__ ((visibility("default")))
-    JNIEnv * GetJNIForThread()
-    {
-        return mozilla::AndroidBridge::JNIForThread();
-    }
-}
-
 jclass GetGeckoAppShellClass()
 {
     return mozilla::AndroidBridge::GetGeckoAppShellClass();
 }
 
 void
 AndroidBridge::ScanMedia(const nsAString& aFile, const nsACString& aMimeType)
 {
-    AutoLocalJNIFrame jniFrame;
-    jstring jstrFile = mJNIEnv->NewString(nsPromiseFlatString(aFile).get(), aFile.Length());
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+    jstring jstrFile = env->NewString(nsPromiseFlatString(aFile).get(), aFile.Length());
 
     nsString mimeType2;
     CopyUTF8toUTF16(aMimeType, mimeType2);
-    jstring jstrMimeTypes = mJNIEnv->NewString(nsPromiseFlatString(mimeType2).get(), mimeType2.Length());
+    jstring jstrMimeTypes = env->NewString(nsPromiseFlatString(mimeType2).get(), mimeType2.Length());
 
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jScanMedia, jstrFile, jstrMimeTypes);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jScanMedia, jstrFile, jstrMimeTypes);
 }
 
 void
 AndroidBridge::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, const nsAString& aIconData, const nsAString& aIntent)
 {
-  AutoLocalJNIFrame jniFrame;
-  jstring jstrTitle = mJNIEnv->NewString(nsPromiseFlatString(aTitle).get(), aTitle.Length());
-  jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
-  jstring jstrIconData = mJNIEnv->NewString(nsPromiseFlatString(aIconData).get(), aIconData.Length());
-  jstring jstrIntent = mJNIEnv->NewString(nsPromiseFlatString(aIntent).get(), aIntent.Length());
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+    jstring jstrTitle = env->NewString(nsPromiseFlatString(aTitle).get(), aTitle.Length());
+    jstring jstrURI = env->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
+    jstring jstrIconData = env->NewString(nsPromiseFlatString(aIconData).get(), aIconData.Length());
+    jstring jstrIntent = env->NewString(nsPromiseFlatString(aIntent).get(), aIntent.Length());
   
-  if (!jstrURI || !jstrTitle || !jstrIconData)
-    return;
+    if (!jstrURI || !jstrTitle || !jstrIconData)
+        return;
     
-  mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCreateShortcut, jstrTitle, jstrURI, jstrIconData, jstrIntent);
+  env->CallStaticVoidMethod(mGeckoAppShellClass, jCreateShortcut, jstrTitle, jstrURI, jstrIconData, jstrIntent);
 }
 
 void
-AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
+AndroidBridge::PostToJavaThread(JNIEnv *env, nsIRunnable* aRunnable, bool aMainThread)
 {
-    JNIEnv* env = AndroidBridge::AttachThread(false);
-    if (!env) {
-        return;
-    }
     mRunnableQueue.AppendObject(aRunnable);
+
+    AutoLocalJNIFrame jniFrame(env);
     env->CallStaticVoidMethod(mGeckoAppShellClass, jPostToJavaThread, (jboolean)aMainThread);
-
-    jthrowable ex = env->ExceptionOccurred();
-    if (ex) {
-        env->ExceptionDescribe();
-        env->ExceptionClear();
-    }
 }
 
 void
-AndroidBridge::ExecuteNextRunnable()
+AndroidBridge::ExecuteNextRunnable(JNIEnv *env)
 {
-    JNIEnv* env = AndroidBridge::AttachThread(false);
-    if (!env) {
-        return;
-    }
-
     if (mRunnableQueue.Count() > 0) {
         nsIRunnable* r = mRunnableQueue[0];
         r->Run();
         mRunnableQueue.RemoveObjectAt(0);
     }
 }
 
 void
@@ -1080,18 +1169,22 @@ AndroidBridge::OpenGraphicsLibraries()
 
             ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess);
         }
     }
 }
 
 void
 AndroidBridge::FireAndWaitForTracerEvent() {
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, 
-                                  jFireAndWaitForTracerEvent);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, 
+                              jFireAndWaitForTracerEvent);
 }
 
 
 namespace mozilla {
     class TracerRunnable : public nsRunnable{
     public:
         TracerRunnable() {
             mTracerLock = new Mutex("TracerRunnable");
@@ -1187,111 +1280,135 @@ AndroidBridge::ValidateBitmap(jobject bi
         uint32_t stride;
         uint32_t format;
         uint32_t flags;
     };
 
     int err;
     struct BitmapInfo info = { 0, };
 
-    if ((err = AndroidBitmap_getInfo(JNI(), bitmap, &info)) != 0) {
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    if ((err = AndroidBitmap_getInfo(env, bitmap, &info)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_getInfo failed! (error %d)", err);
         return false;
     }
 
     if (info.width != width || info.height != height)
         return false;
 
     return true;
 }
 
 bool
 AndroidBridge::InitCamera(const nsCString& contentType, PRUint32 camera, PRUint32 *width, PRUint32 *height, PRUint32 *fps)
 {
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     NS_ConvertASCIItoUTF16 s(contentType);
-    jstring jstrContentType = mJNIEnv->NewString(s.get(), NS_strlen(s.get()));
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jInitCamera, jstrContentType, camera, *width, *height);
+    jstring jstrContentType = env->NewString(s.get(), NS_strlen(s.get()));
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jInitCamera, jstrContentType, camera, *width, *height);
     jintArray arr = static_cast<jintArray>(obj);
     if (!arr)
         return false;
 
-    jint *elements = mJNIEnv->GetIntArrayElements(arr, 0);
+    jint *elements = env->GetIntArrayElements(arr, 0);
 
     *width = elements[1];
     *height = elements[2];
     *fps = elements[3];
 
     bool res = elements[0] == 1;
 
-    mJNIEnv->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr, elements, 0);
 
     return res;
 }
 
 void
 AndroidBridge::CloseCamera() {
-    AutoLocalJNIFrame jniFrame;
 
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera);
 }
 
 void
 AndroidBridge::EnableBatteryNotifications()
 {
     ALOG_BRIDGE("AndroidBridge::EnableBatteryObserver");
 
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications);
 }
 
 void
 AndroidBridge::DisableBatteryNotifications()
 {
     ALOG_BRIDGE("AndroidBridge::DisableBatteryNotifications");
 
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications);
 }
 
 void
 AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want a double and a boolean.
-    jobject obj = mJNIEnv->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformation);
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformation);
     jdoubleArray arr = static_cast<jdoubleArray>(obj);
-    if (!arr || mJNIEnv->GetArrayLength(arr) != 3) {
+    if (!arr || env->GetArrayLength(arr) != 3) {
         return;
     }
 
-    jdouble* info = mJNIEnv->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr, 0);
 
     aBatteryInfo->level() = info[0];
     aBatteryInfo->charging() = info[1] == 1.0f;
     aBatteryInfo->remainingTime() = info[2];
 
-    mJNIEnv->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr, info, 0);
 }
 
 void
 AndroidBridge::HandleGeckoMessage(const nsAString &aMessage, nsAString &aRet)
 {
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
-    JNIEnv* env = AndroidBridge::AttachThread(false);
-    if (!env) {
-        ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
+
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
         return;
-    }
 
-    AutoLocalJNIFrame jniFrame(1);
-    jstring jMessage = mJNIEnv->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length());
+    AutoLocalJNIFrame jniFrame(env, 1);
+    jstring jMessage = env->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length());
     jstring returnMessage =  static_cast<jstring>(env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage));
 
     jthrowable ex = env->ExceptionOccurred();
     if (ex) {
         env->ExceptionDescribe();
         env->ExceptionClear();
     }
     nsJNIString jniStr(returnMessage);
@@ -1305,78 +1422,107 @@ nsCOMPtr<nsIAndroidDrawMetadataProvider>
 AndroidBridge::GetDrawMetadataProvider()
 {
     return gDrawMetadataProvider;
 }
 
 void
 AndroidBridge::CheckURIVisited(const nsAString& aURI)
 {
-  AutoLocalJNIFrame jniFrame(1);
-  jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
-  mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI);
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return;
+   
+   AutoLocalJNIFrame jniFrame(env, 1);
+   jstring jstrURI = env->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
+   env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI);
 }
 
 void
 AndroidBridge::MarkURIVisited(const nsAString& aURI)
 {
-  AutoLocalJNIFrame jniFrame(1);
-  jstring jstrURI = mJNIEnv->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
-  mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI);
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return;
+
+   AutoLocalJNIFrame jniFrame(env, 1);
+   jstring jstrURI = env->NewString(nsPromiseFlatString(aURI).get(), aURI.Length());
+   env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI);
 }
 
 void AndroidBridge::EmitGeckoAccessibilityEvent (PRInt32 eventType, const nsAString& role, const nsAString& text, const nsAString& description, bool enabled, bool checked, bool password) {
-    AutoLocalJNIFrame jniFrame;
-    jstring jstrRole = mJNIEnv->NewString(nsPromiseFlatString(role).get(), role.Length());
-    jstring jstrText = mJNIEnv->NewString(nsPromiseFlatString(text).get(), text.Length());
-    jstring jstrDescription = mJNIEnv->NewString(nsPromiseFlatString(description).get(), description.Length());
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEmitGeckoAccessibilityEvent, eventType, jstrRole, jstrText, jstrDescription, enabled, checked, password);
+
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return;
+
+   AutoLocalJNIFrame jniFrame(env); 
+   jstring jstrRole = env->NewString(nsPromiseFlatString(role).get(), role.Length());
+   jstring jstrText = env->NewString(nsPromiseFlatString(text).get(), text.Length());
+   jstring jstrDescription = env->NewString(nsPromiseFlatString(description).get(), description.Length());
+   env->CallStaticVoidMethod(mGeckoAppShellClass, jEmitGeckoAccessibilityEvent, eventType, jstrRole, jstrText, jstrDescription, enabled, checked, password);
 }
 
 PRUint16
 AndroidBridge::GetNumberOfMessagesForText(const nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::GetNumberOfMessagesForText");
 
-    AutoLocalJNIFrame jniFrame;
-    jstring jText = GetJNIForThread()->NewString(PromiseFlatString(aText).get(), aText.Length());
-    return GetJNIForThread()->CallStaticIntMethod(mGeckoAppShellClass, jNumberOfMessages, jText);
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return 0;
+
+   AutoLocalJNIFrame jniFrame(env); 
+   jstring jText = env->NewString(PromiseFlatString(aText).get(), aText.Length());
+   return env->CallStaticIntMethod(mGeckoAppShellClass, jNumberOfMessages, jText);
 }
 
 void
 AndroidBridge::SendMessage(const nsAString& aNumber, const nsAString& aMessage)
 {
     ALOG_BRIDGE("AndroidBridge::SendMessage");
 
-    AutoLocalJNIFrame jniFrame;
-    jstring jNumber = GetJNIForThread()->NewString(PromiseFlatString(aNumber).get(), aNumber.Length());
-    jstring jMessage = GetJNIForThread()->NewString(PromiseFlatString(aMessage).get(), aMessage.Length());
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return;
+   AutoLocalJNIFrame jniFrame(env);
+   jstring jNumber = env->NewString(PromiseFlatString(aNumber).get(), aNumber.Length());
+   jstring jMessage = env->NewString(PromiseFlatString(aMessage).get(), aMessage.Length());
 
-    GetJNIForThread()->CallStaticVoidMethod(mGeckoAppShellClass, jSendMessage, jNumber, jMessage);
+   env->CallStaticVoidMethod(mGeckoAppShellClass, jSendMessage, jNumber, jMessage);
 }
 
 void *
 AndroidBridge::LockBitmap(jobject bitmap)
 {
     int err;
     void *buf;
 
-    if ((err = AndroidBitmap_lockPixels(JNI(), bitmap, &buf)) != 0) {
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
         buf = nsnull;
     }
 
     return buf;
 }
 
 void
 AndroidBridge::UnlockBitmap(jobject bitmap)
 {
     int err;
-    if ((err = AndroidBitmap_unlockPixels(JNI(), bitmap)) != 0)
+
+   JNIEnv *env = GetJNIEnv();
+   if (!env)
+       return;
+
+   if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0)
         ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
 }
 
 
 bool
 AndroidBridge::HasNativeWindowAccess()
 {
     OpenGraphicsLibraries();
@@ -1385,17 +1531,21 @@ AndroidBridge::HasNativeWindowAccess()
 }
 
 void*
 AndroidBridge::AcquireNativeWindow(jobject surface)
 {
     if (!HasNativeWindowAccess())
         return nsnull;
 
-    return ANativeWindow_fromSurface(JNI(), surface);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    return ANativeWindow_fromSurface(env, surface);
 }
 
 void
 AndroidBridge::ReleaseNativeWindow(void *window)
 {
     if (!window)
         return;
 
@@ -1462,17 +1612,21 @@ AndroidBridge::UnlockWindow(void* window
     }
 
     return true;
 }
 
 bool
 AndroidBridge::IsTablet()
 {
-    return mJNIEnv->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return false;
+
+    return env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
 }
 
 /* Implementation file */
 NS_IMPL_ISUPPORTS1(nsAndroidBridge, nsIAndroidBridge)
 
 nsAndroidBridge::nsAndroidBridge()
 {
 }
@@ -1490,8 +1644,48 @@ NS_IMETHODIMP nsAndroidBridge::HandleGec
 
 /* void SetDrawMetadataProvider (in nsIAndroidDrawMetadataProvider message); */
 NS_IMETHODIMP nsAndroidBridge::SetDrawMetadataProvider(nsIAndroidDrawMetadataProvider *aProvider)
 {
     gDrawMetadataProvider = aProvider;
     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;
+   JavaVM *vm = NULL;
+   env->GetJavaVM(&vm);
+   vm->DetachCurrentThread();
+}
+
+extern "C" {
+   __attribute__ ((visibility("default")))
+   JNIEnv * GetJNIForThread()
+   {
+       JNIEnv *jEnv = NULL;
+       JavaVM *jVm  = mozilla::AndroidBridge::GetVM();
+       if (!jVm) {
+           __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "Returned a null VM");
+           return NULL;
+       }
+       int status = jVm->GetEnv((void**) &jEnv, JNI_VERSION_1_2);
+       if (status < 0) {
+           status = jVm->AttachCurrentThread(&jEnv, NULL);
+           if (status < 0) {
+               __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread",  "Could not attach");
+               return NULL;
+           }
+           static PRUintn sJavaEnvThreadIndex = 0;
+           PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
+           PR_SetThreadPrivate(sJavaEnvThreadIndex, jEnv);
+       }
+       if (!jEnv) {
+           __android_log_print(ANDROID_LOG_INFO, "GetJNIForThread", "returning NULL");
+       }
+       return jEnv;
+   }
+}
--- a/widget/src/android/AndroidBridge.h
+++ b/widget/src/android/AndroidBridge.h
@@ -36,36 +36,44 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef AndroidBridge_h__
 #define AndroidBridge_h__
 
 #include <jni.h>
 #include <android/log.h>
 #include <cstdlib>
+#include <pthread.h>
 
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsIRunnable.h"
 #include "nsIObserver.h"
+#include "nsThreadUtils.h"
 
 #include "AndroidJavaWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
 
 #include "nsIAndroidBridge.h"
 
 // Some debug #defines
 // #define DEBUG_ANDROID_EVENTS
 // #define DEBUG_ANDROID_WIDGET
 
 class nsWindow;
 
+/* See the comment in AndroidBridge about this function before using it */
+extern "C" JNIEnv * GetJNIForThread();
+
+extern bool mozilla_AndroidBridge_SetMainThread(void *);
+extern jclass GetGeckoAppShellClass();
+
 namespace mozilla {
 
 namespace hal {
 class BatteryInformation;
 } // namespace hal
 
 // The order and number of the members in this structure must correspond
 // to the attrsAppearance array in GeckoAppShell.getSystemColors()
@@ -95,44 +103,47 @@ public:
 
     static AndroidBridge *ConstructBridge(JNIEnv *jEnv,
                                           jclass jGeckoAppShellClass);
 
     static AndroidBridge *Bridge() {
         return sBridge;
     }
 
-    static JavaVM *VM() {
-        return sBridge->mJavaVM;
+    static JavaVM *GetVM() {
+        if (NS_LIKELY(sBridge))
+            return sBridge->mJavaVM;
+        return nsnull;
     }
 
-    static JNIEnv *JNI() {
-        sBridge->EnsureJNIThread();
-        return sBridge->mJNIEnv;
-    }
+    static JNIEnv *GetJNIEnv() {
+        if (NS_LIKELY(sBridge)) {
+            if ((void*)pthread_self() != sBridge->mThread) {
+                __android_log_print(ANDROID_LOG_INFO, "AndroidBridge",
+                                    "###!!!!!!! Something's grabbing the JNIEnv from the wrong thread! (thr %p should be %p)",
+                                    (void*)pthread_self(), (void*)sBridge->mThread);
+                return nsnull;
+            }
+            return sBridge->mJNIEnv;
 
-    static JNIEnv *JNIForThread() {
-        if (NS_LIKELY(sBridge))
-          return sBridge->AttachThread();
+        }
         return nsnull;
     }
     
     static jclass GetGeckoAppShellClass() {
         return sBridge->mGeckoAppShellClass;
     }
 
     // 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
     // us to use.  toolkit/xre/nsAndroidStartup.cpp calls
     // SetMainThread.
     bool SetMainThread(void *thr);
 
-    JNIEnv* AttachThread(bool asDaemon = true);
-
     /* These are all implemented in Java */
     static void NotifyIME(int aType, int aState);
 
     static void NotifyIMEEnabled(int aState, const nsAString& aTypeHint,
                                  const nsAString& aActionHint);
 
     static void NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd);
 
@@ -227,48 +238,57 @@ public:
     void FireAndWaitForTracerEvent();
 
     bool GetAccessibilityEnabled();
 
     class AutoLocalJNIFrame {
     public:
         AutoLocalJNIFrame(int nEntries = 128)
             : mEntries(nEntries)
-            , mJNIEnv(JNI())
         {
+            mJNIEnv = AndroidBridge::GetJNIEnv();
             Push();
         }
 
         AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 128)
             : mEntries(nEntries)
-            , mJNIEnv(aJNIEnv ? aJNIEnv : JNI())
         {
+            mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv();
+
             Push();
         }
 
         // Note! Calling Purge makes all previous local refs created in
         // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down
         // any local refs that you need to keep around in global refs!
         void Purge() {
-            mJNIEnv->PopLocalFrame(NULL);
-            Push();
+            if (mJNIEnv) {
+                mJNIEnv->PopLocalFrame(NULL);
+                Push();
+            }
         }
 
         ~AutoLocalJNIFrame() {
+            if (!mJNIEnv)
+                return;
+
             jthrowable exception = mJNIEnv->ExceptionOccurred();
             if (exception) {
                 mJNIEnv->ExceptionDescribe();
                 mJNIEnv->ExceptionClear();
             }
 
             mJNIEnv->PopLocalFrame(NULL);
         }
 
     private:
         void Push() {
+            if (!mJNIEnv)
+                return;
+
             // Make sure there is enough space to store a local ref to the
             // exception.  I am not completely sure this is needed, but does
             // not hurt.
             mJNIEnv->PushLocalFrame(mEntries + 1);
         }
 
         int mEntries;
         JNIEnv* mJNIEnv;
@@ -291,19 +311,19 @@ public:
     bool HasNativeBitmapAccess();
 
     bool ValidateBitmap(jobject bitmap, int width, int height);
 
     void *LockBitmap(jobject bitmap);
 
     void UnlockBitmap(jobject bitmap);
 
-    void PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread = false);
+    void PostToJavaThread(JNIEnv *aEnv, nsIRunnable* aRunnable, bool aMainThread = false);
 
-    void ExecuteNextRunnable();
+    void ExecuteNextRunnable(JNIEnv *aEnv);
 
     /* Copied from Android's native_window.h in newer (platform 9) NDK */
     enum {
         WINDOW_FORMAT_RGBA_8888          = 1,
         WINDOW_FORMAT_RGBX_8888          = 2,
         WINDOW_FORMAT_RGB_565            = 4,
     };
 
@@ -353,18 +373,16 @@ protected:
     AndroidGeckoSoftwareLayerClient mSoftwareLayerClient;
 
     // the GeckoAppShell java class
     jclass mGeckoAppShellClass;
 
     AndroidBridge() { }
     bool Init(JNIEnv *jEnv, jclass jGeckoApp);
 
-    void EnsureJNIThread();
-
     bool mOpenedGraphicsLibraries;
     void OpenGraphicsLibraries();
 
     bool mHasNativeBitmapAccess;
     bool mHasNativeWindowAccess;
 
     nsCOMArray<nsIRunnable> mRunnableQueue;
 
@@ -462,13 +480,10 @@ public:
   nsAndroidBridge();
 
 private:
   ~nsAndroidBridge();
 
 protected:
 };
 
-extern "C" JNIEnv * GetJNIForThread();
-extern bool mozilla_AndroidBridge_SetMainThread(void *);
-extern jclass GetGeckoAppShellClass();
 
 #endif /* AndroidBridge_h__ */
--- a/widget/src/android/AndroidJNI.cpp
+++ b/widget/src/android/AndroidJNI.cpp
@@ -196,24 +196,24 @@ Java_org_mozilla_gecko_GeckoAppShell_rep
     const NS_ConvertUTF16toUTF8 stackTrace8(stackTrace16);
     CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("JavaStackTrace"), stackTrace8);
 #endif // MOZ_CRASHREPORTER
 
     abort();
 }
 
 NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *, jclass)
+Java_org_mozilla_gecko_GeckoAppShell_executeNextRunnable(JNIEnv *jenv, jclass)
 {
     __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "%s", __PRETTY_FUNCTION__);
     if (!AndroidBridge::Bridge()) {
         __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "no bridge in %s!!!!", __PRETTY_FUNCTION__);
         return;
     }
-    AndroidBridge::Bridge()->ExecuteNextRunnable();
+    AndroidBridge::Bridge()->ExecuteNextRunnable(jenv);
     __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", "leaving %s", __PRETTY_FUNCTION__);
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass,
                                                          jdouble aLevel,
                                                          jboolean aCharging,
                                                          jdouble aRemainingTime)
--- a/widget/src/android/AndroidJavaWrappers.cpp
+++ b/widget/src/android/AndroidJavaWrappers.cpp
@@ -112,18 +112,16 @@ jmethodID AndroidGeckoSurfaceView::jBegi
 jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jDraw2DBitmapMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jDraw2DBufferMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBitmapMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jGetSurfaceMethod = 0;
 jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
 
-#define JNI()  (AndroidBridge::JNI())
-
 #define initInit() jclass jClass
 
 // note that this also sets jClass
 #define getClassGlobalRef(cname) \
     (jClass = jclass(jEnv->NewGlobalRef(jEnv->FindClass(cname))))
 
 #define getField(fname, ftype) \
     ((jfieldID) jEnv->GetFieldID(jClass, fname, ftype))
@@ -558,105 +556,158 @@ AndroidGeckoSurfaceView::Init(jobject jo
     wrapped_obj = jobj;
 }
 
 int
 AndroidGeckoSurfaceView::BeginDrawing()
 {
     NS_ASSERTION(!isNull(), "BeginDrawing called on null surfaceview!");
 
-    return JNI()->CallIntMethod(wrapped_obj, jBeginDrawingMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return 0;
+
+    return env->CallIntMethod(wrapped_obj, jBeginDrawingMethod);
 }
 
 void
 AndroidGeckoSurfaceView::EndDrawing()
 {
-    JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallVoidMethod(wrapped_obj, jEndDrawingMethod);
 }
 
 void
 AndroidGeckoSurfaceView::Draw2D(jobject bitmap, int width, int height)
 {
-    JNI()->CallVoidMethod(wrapped_obj, jDraw2DBitmapMethod, bitmap, width, height);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallVoidMethod(wrapped_obj, jDraw2DBitmapMethod, bitmap, width, height);
 }
 
 void
 AndroidGeckoSurfaceView::Draw2D(jobject buffer, int stride)
 {
-    JNI()->CallVoidMethod(wrapped_obj, jDraw2DBufferMethod, buffer, stride);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallVoidMethod(wrapped_obj, jDraw2DBufferMethod, buffer, stride);
 }
 
 jobject
 AndroidGeckoSoftwareLayerClient::LockBuffer()
 {
     NS_ASSERTION(!isNull(), "LockBuffer() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    return JNI()->CallObjectMethod(wrapped_obj, jLockBufferMethod);
+
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    return env->CallObjectMethod(wrapped_obj, jLockBufferMethod);
 }
 
 unsigned char *
 AndroidGeckoSoftwareLayerClient::LockBufferBits()
 {
-    AndroidBridge::AutoLocalJNIFrame(1);
-    jobject bufferObject = LockBuffer();
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
 
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+
+    jobject bufferObject = LockBuffer();
     if (bufferObject != nsnull)
-        return reinterpret_cast<unsigned char *>(JNI()->GetDirectBufferAddress(bufferObject));
+        return reinterpret_cast<unsigned char *>(env->GetDirectBufferAddress(bufferObject));
 
     return nsnull;
 }
 
 void
 AndroidGeckoSoftwareLayerClient::UnlockBuffer()
 {
     NS_ASSERTION(!isNull(), "UnlockBuffer() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    JNI()->CallVoidMethod(wrapped_obj, jUnlockBufferMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    env->CallVoidMethod(wrapped_obj, jUnlockBufferMethod);
 }
 
 void
 AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight)
 {
     NS_ASSERTION(!isNull(), "BeginDrawing() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    return JNI()->CallVoidMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    return env->CallVoidMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight);
 }
 
 void
 AndroidGeckoSoftwareLayerClient::EndDrawing(const nsIntRect &aRect, const nsAString &aMetadata)
 {
     NS_ASSERTION(!isNull(), "EndDrawing() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    jstring jMetadata = JNI()->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length());
-    return JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod, aRect.x, aRect.y, aRect.width,
-                                 aRect.height, jMetadata);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    jstring jMetadata = env->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length());
+    return env->CallVoidMethod(wrapped_obj, jEndDrawingMethod, aRect.x, aRect.y, aRect.width,
+                               aRect.height, jMetadata);
 }
 
 jobject
 AndroidGeckoSurfaceView::GetSoftwareDrawBitmap()
 {
-    return JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBitmapMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    return env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBitmapMethod);
 }
 
 jobject
 AndroidGeckoSurfaceView::GetSoftwareDrawBuffer()
 {
-    return JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    return env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod);
 }
 
 jobject
 AndroidGeckoSurfaceView::GetSurface()
 {
-    return JNI()->CallObjectMethod(wrapped_obj, jGetSurfaceMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    return env->CallObjectMethod(wrapped_obj, jGetSurfaceMethod);
 }
 
 jobject
 AndroidGeckoSurfaceView::GetSurfaceHolder()
 {
-    return JNI()->CallObjectMethod(wrapped_obj, jGetHolderMethod);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return nsnull;
+
+    return env->CallObjectMethod(wrapped_obj, jGetHolderMethod);
 }
 
 void
 AndroidRect::Init(JNIEnv *jenv, jobject jobj)
 {
     NS_ASSERTION(wrapped_obj == nsnull, "Init called on non-null wrapped_obj!");
 
     wrapped_obj = jobj;
@@ -677,17 +728,17 @@ AndroidRect::Init(JNIEnv *jenv, jobject 
 nsJNIString::nsJNIString(jstring jstr, JNIEnv *jenv)
 {
     if (!jstr) {
         SetIsVoid(true);
         return;
     }
     JNIEnv *jni = jenv;
     if (!jni)
-        jni = JNI();
+        jni = AndroidBridge::GetJNIEnv();
     const jchar* jCharPtr = jni->GetStringChars(jstr, NULL);
 
     if (!jCharPtr) {
         SetIsVoid(true);
         return;
     }
 
     jsize len = jni->GetStringLength(jstr);
--- a/widget/src/android/nsWindow.cpp
+++ b/widget/src/android/nsWindow.cpp
@@ -1329,18 +1329,22 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
             sview.Draw2D(bitmap, mBounds.width, mBounds.height);
         } else {
             jobject bytebuf = sview.GetSoftwareDrawBuffer();
             if (!bytebuf) {
                 ALOG("no buffer to draw into - skipping draw");
                 return;
             }
 
-            void *buf = AndroidBridge::JNI()->GetDirectBufferAddress(bytebuf);
-            int cap = AndroidBridge::JNI()->GetDirectBufferCapacity(bytebuf);
+            JNIEnv *env = AndroidBridge::GetJNIEnv();
+            if (!env)
+                return;
+
+            void *buf = env->GetDirectBufferAddress(bytebuf);
+            int cap = env->GetDirectBufferCapacity(bytebuf);
             if (!buf || cap != (mBounds.width * mBounds.height * 2)) {
                 ALOG("### Software drawing, but unexpected buffer size %d expected %d (or no buffer %p)!", cap, mBounds.width * mBounds.height * 2, buf);
                 return;
             }
 
             nsRefPtr<gfxImageSurface> targetSurface =
                 new gfxImageSurface((unsigned char *)buf,
                                     gfxIntSize(mBounds.width, mBounds.height),