Merge last green PGO from inbound to central
authorMarco Bonardo <mbonardo@mozilla.com>
Mon, 30 Jan 2012 11:32:01 +0100
changeset 86922 bfeeb813aef2dfe25a74343034664127d954b274
parent 86911 e33539a90ae2943e1398b2df19fda3d1f10405d1 (current diff)
parent 86921 3068e997f7fd71c43b3e7f8fb624c9fcc1227bf9 (diff)
child 86923 e61dcd6f9bd7f53f5d30463fb7c41b4d9a4564d1
child 86944 18e6dee01897eed8551f0e7e964f92b36891a223
child 90853 ad148677fe8e3aaf78dbd6a75823880fe08f4769
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone12.0a1
Merge last green PGO from inbound to central
--- 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
@@ -2378,17 +2378,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
@@ -745,17 +745,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
@@ -1731,43 +1731,42 @@ bool nsPluginInstanceOwner::AddPluginVie
     mPluginViewAdded = true;
   }
 
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
-  if (mInstance && mObjectFrame && mPluginViewAdded) {
-    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);
-    }
-  }
+  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/gfx/2d/Types.h
+++ b/gfx/2d/Types.h
@@ -63,16 +63,17 @@ enum SurfaceFormat
   FORMAT_B8G8R8A8,
   FORMAT_B8G8R8X8,
   FORMAT_R5G6B5,
   FORMAT_A8
 };
 
 enum BackendType
 {
+  BACKEND_NONE,
   BACKEND_DIRECT2D,
   BACKEND_COREGRAPHICS,
   BACKEND_CAIRO,
   BACKEND_SKIA
 };
 
 enum FontType
 {
new file mode 100644
--- /dev/null
+++ b/gfx/skia/fix-comma-end-enum-list.patch
@@ -0,0 +1,380 @@
+diff --git a/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h b/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h
+--- a/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h
++++ b/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h
+@@ -29,17 +29,17 @@ public:
+     SkString fFontName;
+ 
+     enum FontType {
+         kType1_Font,
+         kType1CID_Font,
+         kCFF_Font,
+         kTrueType_Font,
+         kOther_Font,
+-        kNotEmbeddable_Font,
++        kNotEmbeddable_Font
+     };
+     // The type of the underlying font program.  This field determines which
+     // of the following fields are valid.  If it is kOther_Font or
+     // kNotEmbeddable_Font, the per glyph information will never be populated.
+     FontType fType;
+ 
+     // fMultiMaster may be true for Type1_Font or CFF_Font.
+     bool fMultiMaster;
+@@ -51,17 +51,17 @@ public:
+         kFixedPitch_Style  = 0x00001,
+         kSerif_Style       = 0x00002,
+         kSymbolic_Style    = 0x00004,
+         kScript_Style      = 0x00008,
+         kNonsymbolic_Style = 0x00020,
+         kItalic_Style      = 0x00040,
+         kAllCaps_Style     = 0x10000,
+         kSmallCaps_Style   = 0x20000,
+-        kForceBold_Style   = 0x40000,
++        kForceBold_Style   = 0x40000
+     };
+     uint16_t fStyle;        // Font style characteristics.
+     int16_t fItalicAngle;   // Counterclockwise degrees from vertical of the
+                             // dominant vertical stroke for an Italic face.
+     // The following fields are all in font units.
+     int16_t fAscent;       // Max height above baseline, not including accents.
+     int16_t fDescent;      // Max depth below baseline (negative).
+     int16_t fStemV;        // Thickness of dominant vertical stem.
+@@ -70,26 +70,26 @@ public:
+     SkIRect fBBox;  // The bounding box of all glyphs (in font units).
+ 
+     // The type of advance data wanted.
+     enum PerGlyphInfo {
+       kNo_PerGlyphInfo         = 0x0, // Don't populate any per glyph info.
+       kHAdvance_PerGlyphInfo   = 0x1, // Populate horizontal advance data.
+       kVAdvance_PerGlyphInfo   = 0x2, // Populate vertical advance data.
+       kGlyphNames_PerGlyphInfo = 0x4, // Populate glyph names (Type 1 only).
+-      kToUnicode_PerGlyphInfo  = 0x8, // Populate ToUnicode table, ignored
++      kToUnicode_PerGlyphInfo  = 0x8  // Populate ToUnicode table, ignored
+                                       // for Type 1 fonts
+     };
+ 
+     template <typename Data>
+     struct AdvanceMetric {
+         enum MetricType {
+             kDefault,  // Default advance: fAdvance.count = 1
+             kRange,    // Advances for a range: fAdvance.count = fEndID-fStartID
+-            kRun,      // fStartID-fEndID have same advance: fAdvance.count = 1
++            kRun       // fStartID-fEndID have same advance: fAdvance.count = 1
+         };
+         MetricType fType;
+         uint16_t fStartId;
+         uint16_t fEndId;
+         SkTDArray<Data> fAdvance;
+         SkTScopedPtr<AdvanceMetric<Data> > fNext;
+     };
+ 
+diff --git a/gfx/skia/include/core/SkBlitRow.h b/gfx/skia/include/core/SkBlitRow.h
+--- a/gfx/skia/include/core/SkBlitRow.h
++++ b/gfx/skia/include/core/SkBlitRow.h
+@@ -44,17 +44,17 @@ public:
+ 
+     //! Public entry-point to return a blit function ptr
+     static Proc Factory(unsigned flags, SkBitmap::Config);
+ 
+     ///////////// D32 version
+ 
+     enum Flags32 {
+         kGlobalAlpha_Flag32     = 1 << 0,
+-        kSrcPixelAlpha_Flag32   = 1 << 1,
++        kSrcPixelAlpha_Flag32   = 1 << 1
+     };
+ 
+     /** Function pointer that blends 32bit colors onto a 32bit destination.
+         @param dst  array of dst 32bit colors
+         @param src  array of src 32bit colors (w/ or w/o alpha)
+         @param count number of colors to blend
+         @param alpha global alpha to be applied to all src colors
+      */
+diff --git a/gfx/skia/include/core/SkCanvas.h b/gfx/skia/include/core/SkCanvas.h
+--- a/gfx/skia/include/core/SkCanvas.h
++++ b/gfx/skia/include/core/SkCanvas.h
+@@ -132,17 +132,17 @@ public:
+          * low byte to high byte: B, G, R, A.
+          */
+         kBGRA_Premul_Config8888,
+         kBGRA_Unpremul_Config8888,
+         /**
+          * low byte to high byte: R, G, B, A.
+          */
+         kRGBA_Premul_Config8888,
+-        kRGBA_Unpremul_Config8888,
++        kRGBA_Unpremul_Config8888
+     };
+ 
+     /**
+      *  On success (returns true), copy the canvas pixels into the bitmap.
+      *  On failure, the bitmap parameter is left unchanged and false is
+      *  returned.
+      *
+      *  The canvas' pixels are converted to the bitmap's config. The only
+diff --git a/gfx/skia/include/core/SkDevice.h b/gfx/skia/include/core/SkDevice.h
+--- a/gfx/skia/include/core/SkDevice.h
++++ b/gfx/skia/include/core/SkDevice.h
+@@ -134,17 +134,17 @@ public:
+      *  Return the device's origin: its offset in device coordinates from
+      *  the default origin in its canvas' matrix/clip
+      */
+     const SkIPoint& getOrigin() const { return fOrigin; }
+ 
+ protected:
+     enum Usage {
+        kGeneral_Usage,
+-       kSaveLayer_Usage, // <! internal use only
++       kSaveLayer_Usage // <! internal use only
+     };
+ 
+     struct TextFlags {
+         uint32_t            fFlags;     // SkPaint::getFlags()
+         SkPaint::Hinting    fHinting;
+     };
+ 
+     /**
+diff --git a/gfx/skia/include/core/SkFlattenable.h b/gfx/skia/include/core/SkFlattenable.h
+--- a/gfx/skia/include/core/SkFlattenable.h
++++ b/gfx/skia/include/core/SkFlattenable.h
+@@ -216,17 +216,17 @@ public:
+     SkFactorySet* setFactoryRecorder(SkFactorySet*);
+ 
+     enum Flags {
+         kCrossProcess_Flag       = 0x01,
+         /**
+          *  Instructs the writer to inline Factory names as there are seen the
+          *  first time (after that we store an index). The pipe code uses this.
+          */
+-        kInlineFactoryNames_Flag = 0x02,
++        kInlineFactoryNames_Flag = 0x02
+     };
+     Flags getFlags() const { return (Flags)fFlags; }
+     void setFlags(Flags flags) { fFlags = flags; }
+     
+     bool isCrossProcess() const {
+         return SkToBool(fFlags & kCrossProcess_Flag);
+     }
+     bool inlineFactoryNames() const {
+diff --git a/gfx/skia/include/core/SkFontHost.h b/gfx/skia/include/core/SkFontHost.h
+--- a/gfx/skia/include/core/SkFontHost.h
++++ b/gfx/skia/include/core/SkFontHost.h
+@@ -245,17 +245,17 @@ public:
+         vertically. When rendering subpixel glyphs we need to know which way
+         round they are.
+ 
+         Note, if you change this after startup, you'll need to flush the glyph
+         cache because it'll have the wrong type of masks cached.
+     */
+     enum LCDOrientation {
+         kHorizontal_LCDOrientation = 0,    //!< this is the default
+-        kVertical_LCDOrientation   = 1,
++        kVertical_LCDOrientation   = 1
+     };
+ 
+     static void SetSubpixelOrientation(LCDOrientation orientation);
+     static LCDOrientation GetSubpixelOrientation();
+ 
+     /** LCD color elements can vary in order. For subpixel text we need to know
+         the order which the LCDs uses so that the color fringes are in the
+         correct place.
+@@ -264,17 +264,17 @@ public:
+         cache because it'll have the wrong type of masks cached.
+ 
+         kNONE_LCDOrder means that the subpixel elements are not spatially
+         separated in any usable fashion.
+      */
+     enum LCDOrder {
+         kRGB_LCDOrder = 0,    //!< this is the default
+         kBGR_LCDOrder = 1,
+-        kNONE_LCDOrder = 2,
++        kNONE_LCDOrder = 2
+     };
+ 
+     static void SetSubpixelOrder(LCDOrder order);
+     static LCDOrder GetSubpixelOrder();
+ 
+ #ifdef SK_BUILD_FOR_ANDROID
+     ///////////////////////////////////////////////////////////////////////////
+ 
+diff --git a/gfx/skia/include/core/SkMaskFilter.h b/gfx/skia/include/core/SkMaskFilter.h
+--- a/gfx/skia/include/core/SkMaskFilter.h
++++ b/gfx/skia/include/core/SkMaskFilter.h
+@@ -57,17 +57,17 @@ public:
+ 
+     virtual void flatten(SkFlattenableWriteBuffer& ) {}
+ 
+     enum BlurType {
+         kNone_BlurType,    //!< this maskfilter is not a blur
+         kNormal_BlurType,  //!< fuzzy inside and outside
+         kSolid_BlurType,   //!< solid inside, fuzzy outside
+         kOuter_BlurType,   //!< nothing inside, fuzzy outside
+-        kInner_BlurType,   //!< fuzzy inside, nothing outside
++        kInner_BlurType    //!< fuzzy inside, nothing outside
+     };
+ 
+     struct BlurInfo {
+         SkScalar fRadius;
+         bool     fIgnoreTransform;
+         bool     fHighQuality;
+     };
+ 
+diff --git a/gfx/skia/include/core/SkPaint.h b/gfx/skia/include/core/SkPaint.h
+--- a/gfx/skia/include/core/SkPaint.h
++++ b/gfx/skia/include/core/SkPaint.h
+@@ -70,17 +70,17 @@ public:
+            kFull_Hinting   -> <same as kNormalHinting, unless we are rendering
+                               subpixel glyphs, in which case TARGET_LCD or
+                               TARGET_LCD_V is used>
+     */
+     enum Hinting {
+         kNo_Hinting            = 0,
+         kSlight_Hinting        = 1,
+         kNormal_Hinting        = 2,     //!< this is the default
+-        kFull_Hinting          = 3,
++        kFull_Hinting          = 3
+     };
+ 
+     Hinting getHinting() const {
+         return static_cast<Hinting>(fHinting);
+     }
+ 
+     void setHinting(Hinting hintingLevel);
+ 
+@@ -282,17 +282,17 @@ public:
+         results may not appear the same as if it was drawn twice, filled and
+         then stroked.
+     */
+     enum Style {
+         kFill_Style,            //!< fill the geometry
+         kStroke_Style,          //!< stroke the geometry
+         kStrokeAndFill_Style,   //!< fill and stroke the geometry
+ 
+-        kStyleCount,
++        kStyleCount
+     };
+ 
+     /** Return the paint's style, used for controlling how primitives'
+         geometries are interpreted (except for drawBitmap, which always assumes
+         kFill_Style).
+         @return the paint's Style
+     */
+     Style getStyle() const { return (Style)fStyle; }
+diff --git a/gfx/skia/include/core/SkScalerContext.h b/gfx/skia/include/core/SkScalerContext.h
+--- a/gfx/skia/include/core/SkScalerContext.h
++++ b/gfx/skia/include/core/SkScalerContext.h
+@@ -172,24 +172,24 @@ public:
+         kHintingBit2_Flag         = 0x0100,
+ 
+         // these should only ever be set if fMaskFormat is LCD16 or LCD32
+         kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
+         kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
+ 
+         // luminance : 0 for black text, kLuminance_Max for white text
+         kLuminance_Shift          = 11, // to shift into the other flags above
+-        kLuminance_Bits           = 3,  // ensure Flags doesn't exceed 16bits
++        kLuminance_Bits           = 3  // ensure Flags doesn't exceed 16bits
+     };
+     
+     // computed values
+     enum {
+         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
+         kLuminance_Max  = (1 << kLuminance_Bits) - 1,
+-        kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
++        kLuminance_Mask = kLuminance_Max << kLuminance_Shift
+     };
+ 
+     struct Rec {
+         uint32_t    fOrigFontID;
+         uint32_t    fFontID;
+         SkScalar    fTextSize, fPreScaleX, fPreSkewX;
+         SkScalar    fPost2x2[2][2];
+         SkScalar    fFrameWidth, fMiterLimit;
+diff --git a/gfx/skia/include/core/SkTypes.h b/gfx/skia/include/core/SkTypes.h
+--- a/gfx/skia/include/core/SkTypes.h
++++ b/gfx/skia/include/core/SkTypes.h
+@@ -433,17 +433,17 @@ public:
+          */
+         kAlloc_OnShrink,
+         
+         /**
+          *  If the requested size is smaller than the current size, and the
+          *  current block is dynamically allocated, just return the old
+          *  block.
+          */
+-        kReuse_OnShrink,
++        kReuse_OnShrink
+     };
+ 
+     /**
+      *  Reallocates the block to a new size. The ptr may or may not change.
+      */
+     void* reset(size_t size, OnShrink shrink = kAlloc_OnShrink) {
+         if (size == fSize || (kReuse_OnShrink == shrink && size < fSize)) {
+             return fPtr;
+diff --git a/gfx/skia/include/effects/SkLayerDrawLooper.h b/gfx/skia/include/effects/SkLayerDrawLooper.h
+--- a/gfx/skia/include/effects/SkLayerDrawLooper.h
++++ b/gfx/skia/include/effects/SkLayerDrawLooper.h
+@@ -36,17 +36,17 @@ public:
+         
+         /**
+          *  Use the layer's paint entirely, with these exceptions:
+          *  - We never override the draw's paint's text_encoding, since that is
+          *    used to interpret the text/len parameters in draw[Pos]Text.
+          *  - Flags and Color are always computed using the LayerInfo's
+          *    fFlagsMask and fColorMode.
+          */
+-        kEntirePaint_Bits = -1,
++        kEntirePaint_Bits = -1
+         
+     };
+     typedef int32_t BitFlags;
+ 
+     /**
+      *  Info for how to apply the layer's paint and offset.
+      *
+      *  fFlagsMask selects which flags in the layer's paint should be applied.
+diff --git a/gfx/skia/src/core/SkBitmap.cpp b/gfx/skia/src/core/SkBitmap.cpp
+--- a/gfx/skia/src/core/SkBitmap.cpp
++++ b/gfx/skia/src/core/SkBitmap.cpp
+@@ -1357,17 +1357,17 @@ bool SkBitmap::extractAlpha(SkBitmap* ds
+ 
+ ///////////////////////////////////////////////////////////////////////////////
+ 
+ enum {
+     SERIALIZE_PIXELTYPE_NONE,
+     SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE,
+     SERIALIZE_PIXELTYPE_RAW_NO_CTABLE,
+     SERIALIZE_PIXELTYPE_REF_DATA,
+-    SERIALIZE_PIXELTYPE_REF_PTR,
++    SERIALIZE_PIXELTYPE_REF_PTR
+ };
+ 
+ static void writeString(SkFlattenableWriteBuffer& buffer, const char str[]) {
+     size_t len = strlen(str);
+     buffer.write32(len);
+     buffer.writePad(str, len);
+ }
+ 
+diff --git a/gfx/skia/src/core/SkMatrix.cpp b/gfx/skia/src/core/SkMatrix.cpp
+--- a/gfx/skia/src/core/SkMatrix.cpp
++++ b/gfx/skia/src/core/SkMatrix.cpp
+@@ -1715,17 +1715,17 @@ SkScalar SkMatrix::getMaxStretch() const
+ const SkMatrix& SkMatrix::I() {
+     static SkMatrix gIdentity;
+     static bool gOnce;
+     if (!gOnce) {
+         gIdentity.reset();
+         gOnce = true;
+     }
+     return gIdentity;
+-};
++}
+ 
+ const SkMatrix& SkMatrix::InvalidMatrix() {
+     static SkMatrix gInvalid;
+     static bool gOnce;
+     if (!gOnce) {
+         gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
+                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
+                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
--- a/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h
+++ b/gfx/skia/include/core/SkAdvancedTypefaceMetrics.h
@@ -29,17 +29,17 @@ public:
     SkString fFontName;
 
     enum FontType {
         kType1_Font,
         kType1CID_Font,
         kCFF_Font,
         kTrueType_Font,
         kOther_Font,
-        kNotEmbeddable_Font,
+        kNotEmbeddable_Font
     };
     // The type of the underlying font program.  This field determines which
     // of the following fields are valid.  If it is kOther_Font or
     // kNotEmbeddable_Font, the per glyph information will never be populated.
     FontType fType;
 
     // fMultiMaster may be true for Type1_Font or CFF_Font.
     bool fMultiMaster;
@@ -51,17 +51,17 @@ public:
         kFixedPitch_Style  = 0x00001,
         kSerif_Style       = 0x00002,
         kSymbolic_Style    = 0x00004,
         kScript_Style      = 0x00008,
         kNonsymbolic_Style = 0x00020,
         kItalic_Style      = 0x00040,
         kAllCaps_Style     = 0x10000,
         kSmallCaps_Style   = 0x20000,
-        kForceBold_Style   = 0x40000,
+        kForceBold_Style   = 0x40000
     };
     uint16_t fStyle;        // Font style characteristics.
     int16_t fItalicAngle;   // Counterclockwise degrees from vertical of the
                             // dominant vertical stroke for an Italic face.
     // The following fields are all in font units.
     int16_t fAscent;       // Max height above baseline, not including accents.
     int16_t fDescent;      // Max depth below baseline (negative).
     int16_t fStemV;        // Thickness of dominant vertical stem.
@@ -70,26 +70,26 @@ public:
     SkIRect fBBox;  // The bounding box of all glyphs (in font units).
 
     // The type of advance data wanted.
     enum PerGlyphInfo {
       kNo_PerGlyphInfo         = 0x0, // Don't populate any per glyph info.
       kHAdvance_PerGlyphInfo   = 0x1, // Populate horizontal advance data.
       kVAdvance_PerGlyphInfo   = 0x2, // Populate vertical advance data.
       kGlyphNames_PerGlyphInfo = 0x4, // Populate glyph names (Type 1 only).
-      kToUnicode_PerGlyphInfo  = 0x8, // Populate ToUnicode table, ignored
+      kToUnicode_PerGlyphInfo  = 0x8  // Populate ToUnicode table, ignored
                                       // for Type 1 fonts
     };
 
     template <typename Data>
     struct AdvanceMetric {
         enum MetricType {
             kDefault,  // Default advance: fAdvance.count = 1
             kRange,    // Advances for a range: fAdvance.count = fEndID-fStartID
-            kRun,      // fStartID-fEndID have same advance: fAdvance.count = 1
+            kRun       // fStartID-fEndID have same advance: fAdvance.count = 1
         };
         MetricType fType;
         uint16_t fStartId;
         uint16_t fEndId;
         SkTDArray<Data> fAdvance;
         SkTScopedPtr<AdvanceMetric<Data> > fNext;
     };
 
--- a/gfx/skia/include/core/SkBlitRow.h
+++ b/gfx/skia/include/core/SkBlitRow.h
@@ -44,17 +44,17 @@ public:
 
     //! Public entry-point to return a blit function ptr
     static Proc Factory(unsigned flags, SkBitmap::Config);
 
     ///////////// D32 version
 
     enum Flags32 {
         kGlobalAlpha_Flag32     = 1 << 0,
-        kSrcPixelAlpha_Flag32   = 1 << 1,
+        kSrcPixelAlpha_Flag32   = 1 << 1
     };
 
     /** Function pointer that blends 32bit colors onto a 32bit destination.
         @param dst  array of dst 32bit colors
         @param src  array of src 32bit colors (w/ or w/o alpha)
         @param count number of colors to blend
         @param alpha global alpha to be applied to all src colors
      */
--- a/gfx/skia/include/core/SkCanvas.h
+++ b/gfx/skia/include/core/SkCanvas.h
@@ -132,17 +132,17 @@ public:
          * low byte to high byte: B, G, R, A.
          */
         kBGRA_Premul_Config8888,
         kBGRA_Unpremul_Config8888,
         /**
          * low byte to high byte: R, G, B, A.
          */
         kRGBA_Premul_Config8888,
-        kRGBA_Unpremul_Config8888,
+        kRGBA_Unpremul_Config8888
     };
 
     /**
      *  On success (returns true), copy the canvas pixels into the bitmap.
      *  On failure, the bitmap parameter is left unchanged and false is
      *  returned.
      *
      *  The canvas' pixels are converted to the bitmap's config. The only
--- a/gfx/skia/include/core/SkDevice.h
+++ b/gfx/skia/include/core/SkDevice.h
@@ -134,17 +134,17 @@ public:
      *  Return the device's origin: its offset in device coordinates from
      *  the default origin in its canvas' matrix/clip
      */
     const SkIPoint& getOrigin() const { return fOrigin; }
 
 protected:
     enum Usage {
        kGeneral_Usage,
-       kSaveLayer_Usage, // <! internal use only
+       kSaveLayer_Usage // <! internal use only
     };
 
     struct TextFlags {
         uint32_t            fFlags;     // SkPaint::getFlags()
         SkPaint::Hinting    fHinting;
     };
 
     /**
--- a/gfx/skia/include/core/SkFlattenable.h
+++ b/gfx/skia/include/core/SkFlattenable.h
@@ -216,17 +216,17 @@ public:
     SkFactorySet* setFactoryRecorder(SkFactorySet*);
 
     enum Flags {
         kCrossProcess_Flag       = 0x01,
         /**
          *  Instructs the writer to inline Factory names as there are seen the
          *  first time (after that we store an index). The pipe code uses this.
          */
-        kInlineFactoryNames_Flag = 0x02,
+        kInlineFactoryNames_Flag = 0x02
     };
     Flags getFlags() const { return (Flags)fFlags; }
     void setFlags(Flags flags) { fFlags = flags; }
     
     bool isCrossProcess() const {
         return SkToBool(fFlags & kCrossProcess_Flag);
     }
     bool inlineFactoryNames() const {
--- a/gfx/skia/include/core/SkFontHost.h
+++ b/gfx/skia/include/core/SkFontHost.h
@@ -245,17 +245,17 @@ public:
         vertically. When rendering subpixel glyphs we need to know which way
         round they are.
 
         Note, if you change this after startup, you'll need to flush the glyph
         cache because it'll have the wrong type of masks cached.
     */
     enum LCDOrientation {
         kHorizontal_LCDOrientation = 0,    //!< this is the default
-        kVertical_LCDOrientation   = 1,
+        kVertical_LCDOrientation   = 1
     };
 
     static void SetSubpixelOrientation(LCDOrientation orientation);
     static LCDOrientation GetSubpixelOrientation();
 
     /** LCD color elements can vary in order. For subpixel text we need to know
         the order which the LCDs uses so that the color fringes are in the
         correct place.
@@ -264,17 +264,17 @@ public:
         cache because it'll have the wrong type of masks cached.
 
         kNONE_LCDOrder means that the subpixel elements are not spatially
         separated in any usable fashion.
      */
     enum LCDOrder {
         kRGB_LCDOrder = 0,    //!< this is the default
         kBGR_LCDOrder = 1,
-        kNONE_LCDOrder = 2,
+        kNONE_LCDOrder = 2
     };
 
     static void SetSubpixelOrder(LCDOrder order);
     static LCDOrder GetSubpixelOrder();
 
 #ifdef SK_BUILD_FOR_ANDROID
     ///////////////////////////////////////////////////////////////////////////
 
--- a/gfx/skia/include/core/SkMaskFilter.h
+++ b/gfx/skia/include/core/SkMaskFilter.h
@@ -57,17 +57,17 @@ public:
 
     virtual void flatten(SkFlattenableWriteBuffer& ) {}
 
     enum BlurType {
         kNone_BlurType,    //!< this maskfilter is not a blur
         kNormal_BlurType,  //!< fuzzy inside and outside
         kSolid_BlurType,   //!< solid inside, fuzzy outside
         kOuter_BlurType,   //!< nothing inside, fuzzy outside
-        kInner_BlurType,   //!< fuzzy inside, nothing outside
+        kInner_BlurType    //!< fuzzy inside, nothing outside
     };
 
     struct BlurInfo {
         SkScalar fRadius;
         bool     fIgnoreTransform;
         bool     fHighQuality;
     };
 
--- a/gfx/skia/include/core/SkPaint.h
+++ b/gfx/skia/include/core/SkPaint.h
@@ -70,17 +70,17 @@ public:
            kFull_Hinting   -> <same as kNormalHinting, unless we are rendering
                               subpixel glyphs, in which case TARGET_LCD or
                               TARGET_LCD_V is used>
     */
     enum Hinting {
         kNo_Hinting            = 0,
         kSlight_Hinting        = 1,
         kNormal_Hinting        = 2,     //!< this is the default
-        kFull_Hinting          = 3,
+        kFull_Hinting          = 3
     };
 
     Hinting getHinting() const {
         return static_cast<Hinting>(fHinting);
     }
 
     void setHinting(Hinting hintingLevel);
 
@@ -282,17 +282,17 @@ public:
         results may not appear the same as if it was drawn twice, filled and
         then stroked.
     */
     enum Style {
         kFill_Style,            //!< fill the geometry
         kStroke_Style,          //!< stroke the geometry
         kStrokeAndFill_Style,   //!< fill and stroke the geometry
 
-        kStyleCount,
+        kStyleCount
     };
 
     /** Return the paint's style, used for controlling how primitives'
         geometries are interpreted (except for drawBitmap, which always assumes
         kFill_Style).
         @return the paint's Style
     */
     Style getStyle() const { return (Style)fStyle; }
--- a/gfx/skia/include/core/SkScalerContext.h
+++ b/gfx/skia/include/core/SkScalerContext.h
@@ -172,24 +172,24 @@ public:
         kHintingBit2_Flag         = 0x0100,
 
         // these should only ever be set if fMaskFormat is LCD16 or LCD32
         kLCD_Vertical_Flag        = 0x0200,    // else Horizontal
         kLCD_BGROrder_Flag        = 0x0400,    // else RGB order
 
         // luminance : 0 for black text, kLuminance_Max for white text
         kLuminance_Shift          = 11, // to shift into the other flags above
-        kLuminance_Bits           = 3,  // ensure Flags doesn't exceed 16bits
+        kLuminance_Bits           = 3  // ensure Flags doesn't exceed 16bits
     };
     
     // computed values
     enum {
         kHinting_Mask   = kHintingBit1_Flag | kHintingBit2_Flag,
         kLuminance_Max  = (1 << kLuminance_Bits) - 1,
-        kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
+        kLuminance_Mask = kLuminance_Max << kLuminance_Shift
     };
 
     struct Rec {
         uint32_t    fOrigFontID;
         uint32_t    fFontID;
         SkScalar    fTextSize, fPreScaleX, fPreSkewX;
         SkScalar    fPost2x2[2][2];
         SkScalar    fFrameWidth, fMiterLimit;
--- a/gfx/skia/include/core/SkTypes.h
+++ b/gfx/skia/include/core/SkTypes.h
@@ -433,17 +433,17 @@ public:
          */
         kAlloc_OnShrink,
         
         /**
          *  If the requested size is smaller than the current size, and the
          *  current block is dynamically allocated, just return the old
          *  block.
          */
-        kReuse_OnShrink,
+        kReuse_OnShrink
     };
 
     /**
      *  Reallocates the block to a new size. The ptr may or may not change.
      */
     void* reset(size_t size, OnShrink shrink = kAlloc_OnShrink) {
         if (size == fSize || (kReuse_OnShrink == shrink && size < fSize)) {
             return fPtr;
--- a/gfx/skia/include/effects/SkLayerDrawLooper.h
+++ b/gfx/skia/include/effects/SkLayerDrawLooper.h
@@ -36,17 +36,17 @@ public:
         
         /**
          *  Use the layer's paint entirely, with these exceptions:
          *  - We never override the draw's paint's text_encoding, since that is
          *    used to interpret the text/len parameters in draw[Pos]Text.
          *  - Flags and Color are always computed using the LayerInfo's
          *    fFlagsMask and fColorMode.
          */
-        kEntirePaint_Bits = -1,
+        kEntirePaint_Bits = -1
         
     };
     typedef int32_t BitFlags;
 
     /**
      *  Info for how to apply the layer's paint and offset.
      *
      *  fFlagsMask selects which flags in the layer's paint should be applied.
--- a/gfx/skia/src/core/SkBitmap.cpp
+++ b/gfx/skia/src/core/SkBitmap.cpp
@@ -1357,17 +1357,17 @@ bool SkBitmap::extractAlpha(SkBitmap* ds
 
 ///////////////////////////////////////////////////////////////////////////////
 
 enum {
     SERIALIZE_PIXELTYPE_NONE,
     SERIALIZE_PIXELTYPE_RAW_WITH_CTABLE,
     SERIALIZE_PIXELTYPE_RAW_NO_CTABLE,
     SERIALIZE_PIXELTYPE_REF_DATA,
-    SERIALIZE_PIXELTYPE_REF_PTR,
+    SERIALIZE_PIXELTYPE_REF_PTR
 };
 
 static void writeString(SkFlattenableWriteBuffer& buffer, const char str[]) {
     size_t len = strlen(str);
     buffer.write32(len);
     buffer.writePad(str, len);
 }
 
--- a/gfx/skia/src/core/SkMatrix.cpp
+++ b/gfx/skia/src/core/SkMatrix.cpp
@@ -1715,17 +1715,17 @@ SkScalar SkMatrix::getMaxStretch() const
 const SkMatrix& SkMatrix::I() {
     static SkMatrix gIdentity;
     static bool gOnce;
     if (!gOnce) {
         gIdentity.reset();
         gOnce = true;
     }
     return gIdentity;
-};
+}
 
 const SkMatrix& SkMatrix::InvalidMatrix() {
     static SkMatrix gInvalid;
     static bool gOnce;
     if (!gOnce) {
         gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
--- a/gfx/skia/update.sh
+++ b/gfx/skia/update.sh
@@ -103,9 +103,10 @@ patch -p3 < new-aa.patch
 # Bug 688366 - Fix Skia marking radial gradients with the same radius as invalid.
 patch -p3 < radial-gradients.patch
 # Fix restrict keyword problem for VS2005
 patch -p3 < skia_restrict_problem.patch
 # Changes to SkUserConfig.h - no bug
 patch -p3 < user-config.patch
 # Bug 715718 - Unitialized variable 'margin' in compute_bounds : SkDraw.cpp
 patch -p3 < uninitialized-margin.patch
-
+# Bug 722011 - Fix comma at end of enum list
+patch -p3 < fix-comma-end-enum-list.patch
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -232,16 +232,22 @@ gfxPlatform::gfxPlatform()
 {
     mUseHarfBuzzScripts = UNINITIALIZED_VALUE;
     mAllowDownloadableFonts = UNINITIALIZED_VALUE;
     mDownloadableFontsSanitize = UNINITIALIZED_VALUE;
 #ifdef MOZ_GRAPHITE
     mGraphiteShapingEnabled = UNINITIALIZED_VALUE;
 #endif
     mBidiNumeralOption = UNINITIALIZED_VALUE;
+
+    if (Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
+        mPreferredDrawTargetBackend = BACKEND_SKIA;
+    } else {
+        mPreferredDrawTargetBackend = BACKEND_NONE;
+    }
 }
 
 gfxPlatform*
 gfxPlatform::GetPlatform()
 {
     if (!gPlatform) {
         Init();
     }
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -153,16 +153,18 @@ GetBackendName(mozilla::gfx::BackendType
       case mozilla::gfx::BACKEND_DIRECT2D:
         return "direct2d";
       case mozilla::gfx::BACKEND_COREGRAPHICS:
         return "quartz";
       case mozilla::gfx::BACKEND_CAIRO:
         return "cairo";
       case mozilla::gfx::BACKEND_SKIA:
         return "skia";
+      case mozilla::gfx::BACKEND_NONE:
+        return "none";
       default:
         NS_ERROR("Invalid backend type!");
         return "";
   }
 }
 
 class THEBES_API gfxPlatform {
 public:
@@ -443,16 +445,19 @@ protected:
     PRInt8  mGraphiteShapingEnabled;
 #endif
 
     PRInt8  mBidiNumeralOption;
 
     // which scripts should be shaped with harfbuzz
     PRInt32 mUseHarfBuzzScripts;
 
+    // The preferred draw target backend to use
+    mozilla::gfx::BackendType mPreferredDrawTargetBackend;
+
 private:
     virtual qcms_profile* GetPlatformCMSOutputProfile();
 
     nsRefPtr<gfxASurface> mScreenReferenceSurface;
     nsTArray<PRUint32> mCJKPrefLangs;
     nsCOMPtr<nsIObserver> mSRGBOverrideObserver;
     nsCOMPtr<nsIObserver> mFontPrefsObserver;
     mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureBackendCollector;
--- a/gfx/thebes/gfxPlatformMac.cpp
+++ b/gfx/thebes/gfxPlatformMac.cpp
@@ -158,17 +158,22 @@ gfxPlatformMac::GetScaledFontForFont(gfx
 {
     gfxMacFont *font = static_cast<gfxMacFont*>(aFont);
     return font->GetScaledFont();
 }
 
 bool
 gfxPlatformMac::SupportsAzure(BackendType& aBackend)
 {
-  aBackend = BACKEND_COREGRAPHICS;
+  if (mPreferredDrawTargetBackend != BACKEND_NONE) {
+    aBackend = mPreferredDrawTargetBackend;
+  } else {
+    aBackend = BACKEND_COREGRAPHICS;
+  }
+
   return true;
 }
 
 nsresult
 gfxPlatformMac::ResolveFontName(const nsAString& aFontName,
                                 FontResolverCallback aCallback,
                                 void *aClosure, bool& aAborted)
 {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -547,20 +547,21 @@ gfxWindowsPlatform::SupportsAzure(Backen
 {
 #ifdef CAIRO_HAS_D2D_SURFACE
   if (mRenderMode == RENDER_DIRECT2D) {
       aBackend = BACKEND_DIRECT2D;
       return true;
   }
 #endif
   
-  if (Preferences::GetBool("gfx.canvas.azure.prefer-skia", false)) {
-    aBackend = BACKEND_SKIA;
+  if (mPreferredDrawTargetBackend != BACKEND_NONE) {
+    aBackend = mPreferredDrawTargetBackend;
     return true;
   }
+
   return false;
 }
 
 nsresult
 gfxWindowsPlatform::GetFontList(nsIAtom *aLangGroup,
                                 const nsACString& aGenericFamily,
                                 nsTArray<nsString>& aListOfFonts)
 {
--- a/ipc/chromium/src/base/message_loop.h
+++ b/ipc/chromium/src/base/message_loop.h
@@ -380,17 +380,17 @@ public:
 
   // A queue of non-nestable tasks that we had to defer because when it came
   // time to execute them we were in a nested message loop.  They will execute
   // once we're out of nested message loops.
   TaskQueue deferred_non_nestable_work_queue_;
 
   scoped_refptr<base::MessagePump> pump_;
 
-  ObserverList<DestructionObserver> destruction_observers_;
+  base::ObserverList<DestructionObserver> destruction_observers_;
 
   // A recursion block that prevents accidentally running additonal tasks when
   // insider a (accidentally induced?) nested message pump.
   bool nestable_tasks_allowed_;
 
   bool exception_restoration_;
 
   std::string thread_name_;
--- a/ipc/chromium/src/base/observer_list.h
+++ b/ipc/chromium/src/base/observer_list.h
@@ -11,16 +11,18 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 
 #if defined(ANDROID) && defined(_STLP_STD_NAME)
 using _STLP_STD_NAME::find;
 #endif
 
+namespace base {
+
 ///////////////////////////////////////////////////////////////////////////////
 //
 // OVERVIEW:
 //
 //   A container for a list of observers.  Unlike a normal STL vector or list,
 //   this container can be modified during iteration without invalidating the
 //   iterator.  So, it safely handles the case of an observer removing itself
 //   or other observers from the list while observers are being notified.
@@ -164,17 +166,19 @@ class ObserverList {
   mutable int notify_depth_;
   NotificationType type_;
 
   friend class ObserverList::Iterator;
 
   DISALLOW_EVIL_CONSTRUCTORS(ObserverList);
 };
 
-#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)  \
-  do {                                                        \
-    ObserverList<ObserverType>::Iterator it(observer_list);   \
-    ObserverType* obs;                                        \
-    while ((obs = it.GetNext()) != NULL)                      \
-      obs->func;                                              \
+} // namespace base
+
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)		\
+  do {									\
+    base::ObserverList<ObserverType>::Iterator it(observer_list);	\
+    ObserverType* obs;							\
+    while ((obs = it.GetNext()) != NULL)				\
+      obs->func;							\
   } while (0)
 
 #endif  // BASE_OBSERVER_LIST_H__
--- a/ipc/chromium/src/base/observer_list_threadsafe.h
+++ b/ipc/chromium/src/base/observer_list_threadsafe.h
@@ -10,16 +10,18 @@
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 #include "base/message_loop.h"
 #include "base/observer_list.h"
 #include "base/ref_counted.h"
 #include "base/task.h"
 
+namespace base {
+
 ///////////////////////////////////////////////////////////////////////////////
 //
 // OVERVIEW:
 //
 //   A thread-safe container for a list of observers.
 //   This is similar to the observer_list (see observer_list.h), but it
 //   is more robust for multi-threaded situations.
 //
@@ -191,9 +193,11 @@ class ObserverListThreadSafe
 
   // These are marked mutable to facilitate having NotifyAll be const.
   Lock list_lock_;  // Protects the observer_lists_.
   ObserversListMap observer_lists_;
 
   DISALLOW_EVIL_CONSTRUCTORS(ObserverListThreadSafe);
 };
 
+} // namespace base
+
 #endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
--- a/ipc/chromium/src/base/observer_list_unittest.cc
+++ b/ipc/chromium/src/base/observer_list_unittest.cc
@@ -4,16 +4,17 @@
 
 #include "base/message_loop.h"
 #include "base/observer_list.h"
 #include "base/observer_list_threadsafe.h"
 #include "base/platform_thread.h"
 #include "base/ref_counted.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base;
 using base::Time;
 
 namespace {
 
 class ObserverListTest : public testing::Test {
 };
 
 class Foo {
--- a/ipc/chromium/src/chrome/common/notification_service.h
+++ b/ipc/chromium/src/chrome/common/notification_service.h
@@ -70,17 +70,17 @@ class NotificationService {
   // (for the purpose of registering an observer for events from all sources).
   static Source<void> AllSources() { return Source<void>(NULL); }
 
   // Returns a NotificationDetails object that represents a lack of details
   // associated with a notification.  (This is effectively a null pointer.)
   static Details<void> NoDetails() { return Details<void>(NULL); }
 
  private:
-  typedef ObserverList<NotificationObserver> NotificationObserverList;
+  typedef base::ObserverList<NotificationObserver> NotificationObserverList;
   typedef std::map<uintptr_t, NotificationObserverList*> NotificationSourceMap;
 
   // Convenience function to determine whether a source has a
   // NotificationObserverList in the given map;
   static bool HasKey(const NotificationSourceMap& map,
                      const NotificationSource& source);
 
   // Keeps track of the observers for each type of notification.
--- a/ipc/chromium/src/chrome/common/pref_service.h
+++ b/ipc/chromium/src/chrome/common/pref_service.h
@@ -218,17 +218,17 @@ class PrefService : public NonThreadSafe
   // Helper for safe writing pref data.
   ImportantFileWriter writer_;
 
   // A set of all the registered Preference objects.
   PreferenceSet prefs_;
 
   // A map from pref names to a list of observers.  Observers get fired in the
   // order they are added.
-  typedef ObserverList<NotificationObserver> NotificationObserverList;
+  typedef base::ObserverList<NotificationObserver> NotificationObserverList;
   typedef base::hash_map<std::wstring, NotificationObserverList*>
       PrefObserverMap;
   PrefObserverMap pref_observers_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefService);
 };
 
 #endif  // CHROME_COMMON_PREF_SERVICE_H_
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -27,17 +27,17 @@
 function getElement(id) {
   return ((typeof(id) == "string") ?
     document.getElementById(id) : id); 
 };   
 
 this.$ = this.getElement;
 
 function sendMouseEvent(aEvent, aTarget, aWindow) {
-  if (['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
+  if (['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
     throw new Error("sendMouseEvent doesn't know about event type '" + aEvent.type + "'");
   }
 
   if (!aWindow) {
     aWindow = window;
   }
 
   if (!(aTarget instanceof Element)) {
@@ -47,17 +47,18 @@ function sendMouseEvent(aEvent, aTarget,
   var event = aWindow.document.createEvent('MouseEvent');
 
   var typeArg          = aEvent.type;
   var canBubbleArg     = true;
   var cancelableArg    = true;
   var viewArg          = aWindow;
   var detailArg        = aEvent.detail        || (aEvent.type == 'click'     ||
                                                   aEvent.type == 'mousedown' ||
-                                                  aEvent.type == 'mouseup' ? 1 : 0);
+                                                  aEvent.type == 'mouseup' ? 1 :
+                                                  aEvent.type == 'dblclick'? 2 : 0);
   var screenXArg       = aEvent.screenX       || 0;
   var screenYArg       = aEvent.screenY       || 0;
   var clientXArg       = aEvent.clientX       || 0;
   var clientYArg       = aEvent.clientY       || 0;
   var ctrlKeyArg       = aEvent.ctrlKey       || false;
   var altKeyArg        = aEvent.altKey        || false;
   var shiftKeyArg      = aEvent.shiftKey      || false;
   var metaKeyArg       = aEvent.metaKey       || false;
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgr_sort.js
@@ -109,17 +109,17 @@ function test() {
             // only watch for a confirmation dialog every other time being called
             if (showMode) {
                 Services.ww.registerNotification(function (aSubject, aTopic, aData) {
                     if (aTopic == "domwindowclosed")
                         Services.ww.unregisterNotification(arguments.callee);
                     else if (aTopic == "domwindowopened") {
                         let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
                         SimpleTest.waitForFocus(function() {
-                            EventUtils.synthesizeKey("VK_RETURN", {}, win)
+                            EventUtils.sendKey("RETURN", win);
                         }, win);
                     }
                 });
             }
 
             Services.obs.addObserver(function (aSubject, aTopic, aData) {
                 if (aTopic == "passwordmgr-password-toggle-complete") {
                     Services.obs.removeObserver(arguments.callee, aTopic, false);
--- a/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
+++ b/toolkit/components/passwordmgr/test/browser/browser_passwordmgrdlg.js
@@ -119,17 +119,17 @@ function test() {
             // only watch for a confirmation dialog every other time being called
             if (showMode) {
                 Services.ww.registerNotification(function (aSubject, aTopic, aData) {
                     if (aTopic == "domwindowclosed")
                         Services.ww.unregisterNotification(arguments.callee);
                     else if (aTopic == "domwindowopened") {
                         let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
                         SimpleTest.waitForFocus(function() {
-                            EventUtils.synthesizeKey("VK_RETURN", {}, win)
+                            EventUtils.sendKey("RETURN", win);
                         }, win);
                     }
                 });
             }
 
             Services.obs.addObserver(function (aSubject, aTopic, aData) {
                 if (aTopic == "passwordmgr-password-toggle-complete") {
                     Services.obs.removeObserver(arguments.callee, aTopic, false);
--- a/toolkit/content/aboutSupport.xhtml
+++ b/toolkit/content/aboutSupport.xhtml
@@ -222,24 +222,20 @@
       <!-- - - - - - - - - - - - - - - - - - - - - -->
       <h2 class="major-section">
         &aboutSupport.graphicsTitle;
       </h2>
 
       <table>
         <tbody id="graphics-tbody">
         </tbody>
-      </table>
 
-      <table>
         <tbody id="graphics-info-properties">
         </tbody>
-      </table>
 
-      <table>
         <tbody id="graphics-failures-tbody">
         </tbody>
       </table>
 
     </div>
 
   </body>
 
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -35,52 +35,41 @@
  *
  * ***** 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"
 #include "mozilla/dom/sms/PSms.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().
@@ -88,19 +77,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");
@@ -192,114 +178,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(
@@ -311,86 +247,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())
@@ -418,294 +388,384 @@ 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;
@@ -714,148 +774,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);
 }
 
@@ -864,24 +956,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;
@@ -889,172 +991,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
@@ -1092,18 +1182,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");
@@ -1199,111 +1293,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);
@@ -1317,184 +1435,250 @@ 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, PRInt32 aRequestId, PRUint64 aProcessId)
 {
     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;
 
-    GetJNIForThread()->CallStaticVoidMethod(mGeckoAppShellClass, jSendMessage, jNumber, jMessage, aRequestId, aProcessId);
+    AutoLocalJNIFrame jniFrame(env);
+    jstring jNumber = env->NewString(PromiseFlatString(aNumber).get(), aNumber.Length());
+    jstring jMessage = env->NewString(PromiseFlatString(aMessage).get(), aMessage.Length());
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jSendMessage, jNumber, jMessage, aRequestId, aProcessId);
 }
 
 PRInt32
 AndroidBridge::SaveSentMessage(const nsAString& aRecipient,
                                 const nsAString& aBody, PRUint64 aDate)
 {
     ALOG_BRIDGE("AndroidBridge::SaveSentMessage");
 
-    AutoLocalJNIFrame jniFrame(GetJNIForThread());
-    jstring jRecipient = GetJNIForThread()->NewString(PromiseFlatString(aRecipient).get(), aRecipient.Length());
-    jstring jBody = GetJNIForThread()->NewString(PromiseFlatString(aBody).get(), aBody.Length());
-    return GetJNIForThread()->CallStaticIntMethod(mGeckoAppShellClass, jSaveSentMessage, jRecipient, jBody, aDate);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return 0;
+
+    AutoLocalJNIFrame jniFrame(env, 1);
+    jstring jRecipient = env->NewString(PromiseFlatString(aRecipient).get(), aRecipient.Length());
+    jstring jBody = env->NewString(PromiseFlatString(aBody).get(), aBody.Length());
+    return env->CallStaticIntMethod(mGeckoAppShellClass, jSaveSentMessage, jRecipient, jBody, aDate);
 }
 
 void
 AndroidBridge::GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId)
 {
     ALOG_BRIDGE("AndroidBridge::GetMessage");
 
-    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessage, aMessageId, aRequestId, aProcessId);
+    JNIEnv *env = env;
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessage, aMessageId, aRequestId, aProcessId);
 }
 
 void
 AndroidBridge::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProcessId)
 {
     ALOG_BRIDGE("AndroidBridge::DeleteMessage");
 
-    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessage, aMessageId, aRequestId, aProcessId);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessage, aMessageId, aRequestId, aProcessId);
 }
 
 void
 AndroidBridge::CreateMessageList(const dom::sms::SmsFilterData& aFilter, bool aReverse,
                                  PRInt32 aRequestId, PRUint64 aProcessId)
 {
     ALOG_BRIDGE("AndroidBridge::CreateMessageList");
 
-    AutoLocalJNIFrame jniFrame;
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    AutoLocalJNIFrame jniFrame(env); 
 
     jobjectArray numbers =
-      (jobjectArray)JNI()->NewObjectArray(aFilter.numbers().Length(),
-                                          JNI()->FindClass("java/lang/String"),
-                                          JNI()->NewStringUTF(""));
+      (jobjectArray)env->NewObjectArray(aFilter.numbers().Length(),
+                                          env->FindClass("java/lang/String"),
+                                          env->NewStringUTF(""));
 
     for (PRUint32 i = 0; i < aFilter.numbers().Length(); ++i) {
-      JNI()->SetObjectArrayElement(numbers, i,
-                                   JNI()->NewStringUTF(NS_ConvertUTF16toUTF8(aFilter.numbers()[i]).get()));
+      env->SetObjectArrayElement(numbers, i,
+                                   env->NewStringUTF(NS_ConvertUTF16toUTF8(aFilter.numbers()[i]).get()));
     }
 
-    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jCreateMessageList,
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jCreateMessageList,
                                 aFilter.startDate(), aFilter.endDate(),
                                 numbers, aFilter.numbers().Length(),
                                 aFilter.delivery(), aReverse, aRequestId,
                                 aProcessId);
 }
 
 void
 AndroidBridge::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint64 aProcessId)
 {
     ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
 
-    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageinList, aListId, aRequestId, aProcessId);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageinList, aListId, aRequestId, aProcessId);
 }
 
 void
 AndroidBridge::ClearMessageList(PRInt32 aListId)
 {
     ALOG_BRIDGE("AndroidBridge::ClearMessageList");
 
-    JNI()->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, aListId);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, aListId);
 }
 
 void
 AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
 
-    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, jGetCurrentNetworkInformation);
+    jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformation);
     jdoubleArray arr = static_cast<jdoubleArray>(obj);
-    if (!arr || mJNIEnv->GetArrayLength(arr) != 2) {
+    if (!arr || env->GetArrayLength(arr) != 2) {
         return;
     }
 
-    jdouble* info = mJNIEnv->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr, 0);
 
     aNetworkInfo->bandwidth() = info[0];
     aNetworkInfo->canBeMetered() = info[1] == 1.0f;
 
-    mJNIEnv->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr, info, 0);
 }
 
 void
 AndroidBridge::EnableNetworkNotifications()
 {
     ALOG_BRIDGE("AndroidBridge::EnableNetworkNotifications");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications);
 }
 
 void
 AndroidBridge::DisableNetworkNotifications()
 {
     ALOG_BRIDGE("AndroidBridge::DisableNetworkNotifications");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications);
 }
 
 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();
@@ -1503,17 +1687,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;
 
@@ -1580,17 +1768,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()
 {
 }
@@ -1611,11 +1803,57 @@ NS_IMETHODIMP nsAndroidBridge::SetDrawMe
 {
     gDrawMetadataProvider = aProvider;
     return NS_OK;
 }
 
 void
 AndroidBridge::PreventPanning() {
     ALOG_BRIDGE("AndroidBridge::PreventPanning");
-    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jPreventPanning);
+    JNIEnv *env = GetJNIEnv();
+    if (!env)
+        return;
+
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jPreventPanning);
+}
+
+
+// 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/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -36,37 +36,45 @@
  * ***** 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;
 class nsIDOMMozSmsMessage;
 
+/* 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;
 class NetworkInformation;
 } // namespace hal
 
 namespace dom {
@@ -103,44 +111,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);
 
@@ -237,48 +248,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;
@@ -301,19 +321,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,
     };
 
@@ -373,18 +393,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;
 
@@ -493,13 +511,10 @@ public:
   nsAndroidBridge();
 
 private:
   ~nsAndroidBridge();
 
 protected:
 };
 
-extern "C" JNIEnv * GetJNIForThread();
-extern bool mozilla_AndroidBridge_SetMainThread(void *);
-extern jclass GetGeckoAppShellClass();
 
 #endif /* AndroidBridge_h__ */
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -213,24 +213,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/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -119,18 +119,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))
@@ -603,112 +601,169 @@ 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);
+    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::GetRenderOffset(nsIntPoint &aOffset)
 {
-    AndroidPoint offset(JNI(), JNI()->CallObjectMethod(wrapped_obj, jGetRenderOffsetMethod));
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    AndroidPoint offset(env, env->CallObjectMethod(wrapped_obj, jGetRenderOffsetMethod));
     aOffset.x = offset.X();
     aOffset.y = offset.Y();
 }
 
 bool
 AndroidGeckoSoftwareLayerClient::BeginDrawing(int aWidth, int aHeight, int aTileWidth, int aTileHeight, const nsAString &aMetadata, bool aHasDirectTexture)
 {
     NS_ASSERTION(!isNull(), "BeginDrawing() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    jstring jMetadata = JNI()->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length());
-    return JNI()->CallBooleanMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight, aTileWidth, aTileHeight, jMetadata, aHasDirectTexture);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return false;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    jstring jMetadata = env->NewString(nsPromiseFlatString(aMetadata).get(), aMetadata.Length());
+    return env->CallBooleanMethod(wrapped_obj, jBeginDrawingMethod, aWidth, aHeight, aTileWidth, aTileHeight, jMetadata, aHasDirectTexture);
 }
 
 void
 AndroidGeckoSoftwareLayerClient::EndDrawing(const nsIntRect &aRect)
 {
     NS_ASSERTION(!isNull(), "EndDrawing() called on null software layer client!");
-    AndroidBridge::AutoLocalJNIFrame(1);
-    return JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod, aRect.x, aRect.y, aRect.width, aRect.height);
+    JNIEnv *env = AndroidBridge::GetJNIEnv();
+    if (!env)
+        return;
+
+    AndroidBridge::AutoLocalJNIFrame(env, 1);
+    return env->CallVoidMethod(wrapped_obj, jEndDrawingMethod, aRect.x, aRect.y, aRect.width, aRect.height);
 }
 
 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;
@@ -729,17 +784,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/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -1347,18 +1347,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),
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -1730,17 +1730,17 @@ GCGraphBuilder::NoteRoot(PRUint32 langID
 {
     NS_ASSERTION(root, "Don't add a null root!");
 
     if (langID > nsIProgrammingLanguage::MAX || !mRuntimes[langID]) {
         Fault("adding root for unregistered language", root);
         return;
     }
 
-    if (!participant->CanSkipThis(root)) {
+    if (!participant->CanSkipThis(root) || WantAllTraces()) {
         AddNode(root, participant, langID);
     }
 }
 
 NS_IMETHODIMP_(void)
 GCGraphBuilder::DescribeRefCountedNode(nsrefcnt refCount, size_t objSz,
                                        const char *objName)
 {
@@ -1786,17 +1786,17 @@ GCGraphBuilder::NoteXPCOMChild(nsISuppor
 
 #ifdef DEBUG_CC
     if (nsCycleCollector_shouldSuppress(child))
         return;
 #endif
     
     nsXPCOMCycleCollectionParticipant *cp;
     ToParticipant(child, &cp);
-    if (cp && !cp->CanSkipThis(child)) {
+    if (cp && (!cp->CanSkipThis(child) || WantAllTraces())) {
 
         PtrInfo *childPi = AddNode(child, cp, nsIProgrammingLanguage::CPLUSPLUS);
         if (!childPi)
             return;
         mEdgeBuilder.Add(childPi);
 #ifdef DEBUG_CC
         mCurrPi->mEdgeNames.AppendElement(edgeName);
 #endif
@@ -1920,17 +1920,17 @@ AddPurpleRoot(GCGraphBuilder &builder, n
 {
     root = canonicalize(root);
     NS_ASSERTION(root,
                  "Don't add objects that don't participate in collection!");
 
     nsXPCOMCycleCollectionParticipant *cp;
     ToParticipant(root, &cp);
 
-    if (!cp->CanSkipInCC(root)) {
+    if (builder.WantAllTraces() || !cp->CanSkipInCC(root)) {
         PtrInfo *pinfo = builder.AddNode(root, cp,
                                          nsIProgrammingLanguage::CPLUSPLUS);
         if (!pinfo) {
             return false;
         }
     }
 
     cp->UnmarkPurple(root);
@@ -3727,17 +3727,23 @@ public:
     {
         NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     }
 
     PRUint32 Collect(nsICycleCollectorListener* aListener)
     {
         NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-        mCollector->GCIfNeeded(false);
+        // On a WantAllTraces CC, force a synchronous global GC to prevent
+        // hijinks from ForgetSkippable and compartmental GCs.
+        bool wantAllTraces = false;
+        if (aListener) {
+            aListener->GetWantAllTraces(&wantAllTraces);
+        }
+        mCollector->GCIfNeeded(wantAllTraces);
 
         MutexAutoLock autoLock(mLock);
 
         if (!mRunning)
             return 0;
 
         nsAutoTArray<PtrInfo*, 4000> whiteNodes;
         if (!mCollector->PrepareForCollection(&whiteNodes))