Bug 730890 - Set up an Android Looper on the main Gecko thread r=cjones
☠☠ backed out by 2cd7a0d63346 ☠ ☠
authorJames Willcox <jwillcox@mozilla.com>
Wed, 11 Apr 2012 11:43:08 -0400
changeset 91439 022be5c5073244276e949327f7339cf7f8335389
parent 91438 f03124b0099079ddb74fca4006fb2efeb15a6836
child 91440 ed7531e3906623539ba95963ab9c3d17082ab1bb
push id672
push usertim.taubert@gmx.de
push dateFri, 13 Apr 2012 10:22:59 +0000
treeherderfx-team@cb2e81306595 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs730890
milestone14.0a1
Bug 730890 - Set up an Android Looper on the main Gecko thread r=cjones
dom/plugins/base/android/ANPEvent.cpp
ipc/glue/MessagePump.cpp
mobile/android/base/GeckoAppShell.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
--- a/dom/plugins/base/android/ANPEvent.cpp
+++ b/dom/plugins/base/android/ANPEvent.cpp
@@ -62,30 +62,21 @@ private:
   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(env,
-                                                     new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions),
-                                                     true);
+  PluginEventRunnable* e = new PluginEventRunnable(inst, const_cast<ANPEvent*>(event), pluginFunctions);
+  
+  NS_DispatchToMainThread(e);
   LOG("returning from %s", __PRETTY_FUNCTION__);
 }
 
 
 void InitEventInterface(ANPEventInterfaceV0 *i) {
   _assert(i->inSize == sizeof(*i));
   ASSIGN(i, postEvent);
 }
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -42,16 +42,20 @@
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "pratom.h"
 #include "prthread.h"
 
 #include "base/logging.h"
 #include "base/scoped_nsautorelease_pool.h"
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "AndroidBridge.h"
+#endif
+
 using mozilla::ipc::DoWorkRunnable;
 using mozilla::ipc::MessagePump;
 using mozilla::ipc::MessagePumpForChildProcess;
 using base::Time;
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(DoWorkRunnable, nsIRunnable, nsITimerCallback)
 
 NS_IMETHODIMP
@@ -106,16 +110,20 @@ MessagePump::Run(MessagePump::Delegate* 
 
   for (;;) {
     autoReleasePool.Recycle();
 
     bool did_work = NS_ProcessNextEvent(mThread, false) ? true : false;
     if (!keep_running_)
       break;
 
+#ifdef MOZ_WIDGET_ANDROID
+    AndroidBridge::Bridge()->PumpMessageLoop();
+#endif
+
     did_work |= aDelegate->DoWork();
     if (!keep_running_)
       break;
 
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
 
     if (did_work && delayed_work_time_.is_null())
       mDelayedWorkTimer->Cancel();
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -132,16 +132,18 @@ public class GeckoAppShell
     private static Sensor gAccelerometerSensor = null;
     private static Sensor gLinearAccelerometerSensor = null;
     private static Sensor gGyroscopeSensor = null;
     private static Sensor gOrientationSensor = null;
     private static Sensor gProximitySensor = null;
 
     private static boolean mLocationHighAccuracy = false;
 
+    private static Handler sGeckoHandler;
+
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void nativeInit();
     public static native void nativeRun(String args);
 
     // helper methods
     //    public static native void setSurfaceView(GeckoSurfaceView sv);
@@ -237,16 +239,20 @@ public class GeckoAppShell
         }
     }
 
     // Get a Handler for the main java thread
     public static Handler getMainHandler() {
         return GeckoApp.mAppContext.mMainHandler;
     }
 
+    public static Handler getGeckoHandler() {
+        return sGeckoHandler;
+    }
+
     public static Handler getHandler() {
         return GeckoBackgroundThread.getHandler();
     }
 
     public static File getCacheDir(Context context) {
         if (sCacheFile == null)
             sCacheFile = context.getCacheDir();
         return sCacheFile;
@@ -426,16 +432,19 @@ public class GeckoAppShell
 
             GeckoAppShell.putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
             GeckoAppShell.putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
             GeckoAppShell.putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
         }
     }
 
     public static void runGecko(String apkPath, String args, String url, boolean restoreSession) {
+        Looper.prepare();
+        sGeckoHandler = new Handler();
+
         // run gecko -- it will spawn its own thread
         GeckoAppShell.nativeInit();
 
         Log.i(LOGTAG, "post native init");
 
         // Tell Gecko where the target byte buffer is for rendering
         GeckoAppShell.setLayerClient(GeckoApp.mAppContext.getLayerClient());
 
@@ -2046,16 +2055,33 @@ public class GeckoAppShell
     public static void lockScreenOrientation(int aOrientation) {
         GeckoScreenOrientationListener.getInstance().lockScreenOrientation(aOrientation);
     }
 
     public static void unlockScreenOrientation() {
         GeckoScreenOrientationListener.getInstance().unlockScreenOrientation();
     }
 
+    public static void pumpMessageLoop() {
+        // We're going to run the Looper below, but we need a way to break out, so
+        // we post this Runnable that causes a divide by zero error. The Runnable
+        // is added to the end of the queue, so it will be executed after anything
+        // else that has been added prior.
+        sGeckoHandler.post(new Runnable() {
+            public void run() {
+                int zero = 0;
+                int foo = 0xdeadbeef / zero;
+            }
+        });
+        
+        try {
+            Looper.loop();
+        } catch(Exception ex) {}
+    }
+
     static class AsyncResultHandler extends GeckoApp.FilePickerResultHandler {
         private long mId;
         AsyncResultHandler(long id) {
             mId = id;
         }
 
         public void onActivityResult(int resultCode, Intent data) {
             GeckoAppShell.notifyFilePickerResult(handleActivityResult(resultCode, data), mId);
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -186,16 +186,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
     jDisableNetworkNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableNetworkNotifications", "()V");
     jEmitGeckoAccessibilityEvent = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "emitGeckoAccessibilityEvent", "(I[Ljava/lang/String;Ljava/lang/String;ZZZ)V");
 
     jGetScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getScreenOrientation", "()S");
     jEnableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableScreenOrientationNotifications", "()V");
     jDisableScreenOrientationNotifications = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableScreenOrientationNotifications", "()V");
     jLockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "lockScreenOrientation", "(I)V");
     jUnlockScreenOrientation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "unlockScreenOrientation", "()V");
+    jPumpMessageLoop = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "pumpMessageLoop", "()V");
 
     jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
     jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
     jEGLSurfaceImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLSurfaceImpl"));
     jEGLContextImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLContextImpl"));
     jEGLConfigImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLConfigImpl"));
     jEGLDisplayImplClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("com/google/android/gles_jni/EGLDisplayImpl"));
 
@@ -2125,16 +2126,25 @@ AndroidBridge::LockScreenOrientation(con
 
 void
 AndroidBridge::UnlockScreenOrientation()
 {
   ALOG_BRIDGE("AndroidBridge::UnlockScreenOrientation");
   mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation);
 }
 
+void
+AndroidBridge::PumpMessageLoop()
+{
+    if (!mJNIEnv)
+        return;
+
+    mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jPumpMessageLoop);
+}
+
 /* attribute nsIAndroidBrowserApp browserApp; */
 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
 {
     if (nsAppShell::gAppShell)
         nsAppShell::gAppShell->GetBrowserApp(aBrowserApp);
     return NS_OK;
 }
 NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp)
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -432,16 +432,18 @@ public:
     // headers which requires including basictypes.h which requires a lot of
     // changes...
     void GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation);
     void EnableScreenOrientationNotifications();
     void DisableScreenOrientationNotifications();
     void LockScreenOrientation(const dom::ScreenOrientationWrapper& aOrientation);
     void UnlockScreenOrientation();
 
+    void PumpMessageLoop();
+
 protected:
     static AndroidBridge *sBridge;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
@@ -543,16 +545,17 @@ protected:
     jmethodID jEnableNetworkNotifications;
     jmethodID jDisableNetworkNotifications;
 
     jmethodID jGetScreenOrientation;
     jmethodID jEnableScreenOrientationNotifications;
     jmethodID jDisableScreenOrientationNotifications;
     jmethodID jLockScreenOrientation;
     jmethodID jUnlockScreenOrientation;
+    jmethodID jPumpMessageLoop;
 
     // stuff we need for CallEglCreateWindowSurface
     jclass jEGLSurfaceImplClass;
     jclass jEGLContextImplClass;
     jclass jEGLConfigImplClass;
     jclass jEGLDisplayImplClass;
     jclass jEGLContextClass;
     jclass jEGL10Class;