Bug 846774 - Replace the sync event with an ack flag on events. r=cpeterson a=bajaj
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 18 Mar 2013 23:00:05 +0100
changeset 132422 bab7bc14c912b7d8455abfe5dc68420653a69caa
parent 132421 dc0ea82288b57ecaa7c3f5d7e0dca19a6ca585ce
child 132423 a7232156dacee23add5d37de37e3e91c6e71510b
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpeterson, bajaj
bugs846774
milestone21.0a2
Bug 846774 - Replace the sync event with an ack flag on events. r=cpeterson a=bajaj
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoEvent.java
mobile/android/base/MemoryMonitor.java
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJavaWrappers.cpp
widget/android/AndroidJavaWrappers.h
widget/android/nsAppShell.cpp
widget/android/nsWindow.cpp
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -319,21 +319,16 @@ public class GeckoAppShell
     public static void sendEventToGecko(GeckoEvent e) {
         if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
             notifyGeckoOfEvent(e);
         } else {
             gPendingEvents.addLast(e);
         }
     }
 
-    public static void sendEventToGeckoSync(GeckoEvent e) {
-        sendEventToGecko(e);
-        geckoEventSync();
-    }
-
     // Tell the Gecko event loop that an event is available.
     public static native void notifyGeckoOfEvent(GeckoEvent event);
 
     /*
      *  The Gecko-side API: API methods that Gecko calls
      */
     public static void notifyIME(int type, int state) {
         if (mEditableListener != null) {
@@ -357,58 +352,60 @@ public class GeckoAppShell
     public static void notifyIMEChange(String text, int start, int end, int newEnd) {
         if (newEnd < 0) { // Selection change
             mEditableListener.onSelectionChange(start, end);
         } else { // Text change
             mEditableListener.onTextChange(text, start, end, newEnd);
         }
     }
 
-    private static final GeckoEvent sSyncEvent = GeckoEvent.createSyncEvent();
-    private static boolean sWaitingForSyncAck;
+    private static final Object sEventAckLock = new Object();
+    private static boolean sWaitingForEventAck;
 
     // Block the current thread until the Gecko event loop is caught up
-    public static void geckoEventSync() {
+    public static void sendEventToGeckoSync(GeckoEvent e) {
+        e.setAckNeeded(true);
+
         long time = SystemClock.uptimeMillis();
         boolean isMainThread = (GeckoApp.mAppContext.getMainLooper().getThread() == Thread.currentThread());
 
-        synchronized (sSyncEvent) {
-            if (sWaitingForSyncAck) {
+        synchronized (sEventAckLock) {
+            if (sWaitingForEventAck) {
                 // should never happen since we always leave it as false when we exit this function.
                 Log.e(LOGTAG, "geckoEventSync() may have been called twice concurrently!", new Exception());
                 // fall through for graceful handling
             }
 
-            GeckoAppShell.sendEventToGecko(sSyncEvent);
-            sWaitingForSyncAck = true;
+            sendEventToGecko(e);
+            sWaitingForEventAck = true;
             while (true) {
                 try {
-                    sSyncEvent.wait(100);
+                    sEventAckLock.wait(100);
                 } catch (InterruptedException ie) {
                 }
-                if (!sWaitingForSyncAck) {
+                if (!sWaitingForEventAck) {
                     // response received
                     break;
                 }
                 long waited = SystemClock.uptimeMillis() - time;
                 Log.d(LOGTAG, "Gecko event sync taking too long: " + waited + "ms");
                 if (isMainThread && waited >= 4000) {
                     Log.w(LOGTAG, "Gecko event sync took too long, aborting!", new Exception());
-                    sWaitingForSyncAck = false;
+                    sWaitingForEventAck = false;
                     break;
                 }
             }
         }
     }
 
     // Signal the Java thread that it's time to wake up
-    public static void acknowledgeEventSync() {
-        synchronized (sSyncEvent) {
-            sWaitingForSyncAck = false;
-            sSyncEvent.notifyAll();
+    public static void acknowledgeEvent() {
+        synchronized (sEventAckLock) {
+            sWaitingForEventAck = false;
+            sEventAckLock.notifyAll();
         }
     }
 
     public static void enableLocation(final boolean enable) {
         getMainHandler().post(new Runnable() { 
                 public void run() {
                     LocationManager lm = (LocationManager)
                         GeckoApp.mAppContext.getSystemService(Context.LOCATION_SERVICE);
--- a/mobile/android/base/GeckoEvent.java
+++ b/mobile/android/base/GeckoEvent.java
@@ -44,17 +44,17 @@ public class GeckoEvent {
     private static final int LOCATION_EVENT = 5;
     private static final int IME_EVENT = 6;
     private static final int DRAW = 7;
     private static final int SIZE_CHANGED = 8;
     private static final int ACTIVITY_STOPPING = 9;
     private static final int ACTIVITY_PAUSING = 10;
     private static final int ACTIVITY_SHUTDOWN = 11;
     private static final int LOAD_URI = 12;
-    private static final int GECKO_EVENT_SYNC = 15;
+    private static final int NOOP = 15;
     private static final int ACTIVITY_START = 17;
     private static final int BROADCAST = 19;
     private static final int VIEWPORT = 20;
     private static final int VISITED = 21;
     private static final int NETWORK_CHANGED = 22;
     private static final int ACTIVITY_RESUMING = 24;
     private static final int THUMBNAIL = 25;
     private static final int SCREENORIENTATION_CHANGED = 27;
@@ -100,16 +100,17 @@ public class GeckoEvent {
     public static final int IME_RANGE_LINECOLOR = 8;
 
     public static final int ACTION_MAGNIFY_START = 11;
     public static final int ACTION_MAGNIFY = 12;
     public static final int ACTION_MAGNIFY_END = 13;
 
     final public int mType;
     public int mAction;
+    public boolean mAckNeeded;
     public long mTime;
     public Point[] mPoints;
     public int[] mPointIndicies;
     public int mPointerIndex; // index of the point that has changed
     public float[] mOrientations;
     public float[] mPressures;
     public Point[] mPointRadii;
     public Rect mRect;
@@ -164,18 +165,18 @@ public class GeckoEvent {
         event.mFlags = isApplicationInBackground ? 0 : 1;
         return event;
     }
 
     public static GeckoEvent createShutdownEvent() {
         return new GeckoEvent(ACTIVITY_SHUTDOWN);
     }
 
-    public static GeckoEvent createSyncEvent() {
-        return new GeckoEvent(GECKO_EVENT_SYNC);
+    public static GeckoEvent createNoOpEvent() {
+        return new GeckoEvent(NOOP);
     }
 
     public static GeckoEvent createKeyEvent(KeyEvent k) {
         GeckoEvent event = new GeckoEvent(KEY_EVENT);
         event.initKeyEvent(k);
         return event;
     }
 
@@ -597,9 +598,13 @@ public class GeckoEvent {
         return event;
     }
 
     public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) {
         GeckoEvent event = new GeckoEvent(SCREENORIENTATION_CHANGED);
         event.mScreenOrientation = aScreenOrientation;
         return event;
     }
+
+    public void setAckNeeded(boolean ackNeeded) {
+        mAckNeeded = ackNeeded;
+    }
 }
--- a/mobile/android/base/MemoryMonitor.java
+++ b/mobile/android/base/MemoryMonitor.java
@@ -69,17 +69,17 @@ class MemoryMonitor extends BroadcastRec
         context.getApplicationContext().registerReceiver(this, filter);
     }
 
     public void onLowMemory() {
         Log.d(LOGTAG, "onLowMemory() notification received");
         if (increaseMemoryPressure(MEMORY_PRESSURE_HIGH)) {
             // We need to wait on Gecko here, because if we haven't reduced
             // memory usage enough when we return from this, Android will kill us.
-            GeckoAppShell.geckoEventSync();
+            GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createNoOpEvent());
         }
     }
 
     public void onTrimMemory(int level) {
         Log.d(LOGTAG, "onTrimMemory() notification received with level " + level);
         if (Build.VERSION.SDK_INT < 14) {
             // this won't even get called pre-ICS
             return;
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -103,17 +103,17 @@ AndroidBridge::Init(JNIEnv *jEnv,
     mGeckoAppShellClass = (jclass) jEnv->NewGlobalRef(jGeckoAppShellClass);
 
     jclass jAndroidSmsMessageClass = jEnv->FindClass("android/telephony/SmsMessage");
     mAndroidSmsMessageClass = (jclass) jEnv->NewGlobalRef(jAndroidSmsMessageClass);
 
     jNotifyIME = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIME", "(II)V");
     jNotifyIMEEnabled = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEEnabled", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V");
     jNotifyIMEChange = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
-    jAcknowledgeEventSync = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEventSync", "()V");
+    jAcknowledgeEvent = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "acknowledgeEvent", "()V");
 
     jEnableLocation = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocation", "(Z)V");
     jEnableLocationHighAccuracy = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V");
     jEnableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "enableSensor", "(I)V");
     jDisableSensor = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "disableSensor", "(I)V");
     jScheduleRestart = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "scheduleRestart", "()V");
     jNotifyXreExit = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "onXreExit", "()V");
     jGetHandlersForMimeType = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
@@ -351,26 +351,26 @@ AndroidBridge::NotifyIMEChange(const PRU
     args[1].i = aStart;
     args[2].i = aEnd;
     args[3].i = aNewEnd;
     env->CallStaticVoidMethodA(sBridge->mGeckoAppShellClass,
                                sBridge->jNotifyIMEChange, args);
 }
 
 void
-AndroidBridge::AcknowledgeEventSync()
+AndroidBridge::AcknowledgeEvent()
 {
-    ALOG_BRIDGE("AndroidBridge::AcknowledgeEventSync");
+    ALOG_BRIDGE("AndroidBridge::AcknowledgeEvent");
 
     JNIEnv *env = GetJNIEnv();
     if (!env)
         return;
 
     AutoLocalJNIFrame jniFrame(env, 0);
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync);
+    env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEvent);
 }
 
 void
 AndroidBridge::EnableLocation(bool aEnable)
 {
     ALOG_BRIDGE("AndroidBridge::EnableLocation");
 
     JNIEnv *env = GetJNIEnv();
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -160,17 +160,17 @@ public:
     static void NotifyIMEChange(const PRUnichar *aText, uint32_t aTextLen, int aStart, int aEnd, int aNewEnd);
 
     nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer);
     void SendThumbnail(jobject buffer, int32_t tabId, bool success);
     nsresult GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
 
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const gfx::Rect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical, gfx::Rect& aViewport, float& aScaleX, float& aScaleY);
 
-    void AcknowledgeEventSync();
+    void AcknowledgeEvent();
 
     void EnableLocation(bool aEnable);
     void EnableLocationHighAccuracy(bool aEnable);
 
     void EnableSensor(int aSensorType);
 
     void DisableSensor(int aSensorType);
 
@@ -409,17 +409,17 @@ protected:
     int mAPIVersion;
 
     bool QueueSmsRequest(nsISmsRequest* aRequest, uint32_t* aRequestIdOut);
 
     // other things
     jmethodID jNotifyIME;
     jmethodID jNotifyIMEEnabled;
     jmethodID jNotifyIMEChange;
-    jmethodID jAcknowledgeEventSync;
+    jmethodID jAcknowledgeEvent;
     jmethodID jEnableLocation;
     jmethodID jEnableLocationHighAccuracy;
     jmethodID jEnableSensor;
     jmethodID jDisableSensor;
     jmethodID jNotifyAppShellReady;
     jmethodID jNotifyXreExit;
     jmethodID jScheduleRestart;
     jmethodID jGetOutstandingDrawEvents;
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -7,16 +7,17 @@
 #include "AndroidBridge.h"
 #include "nsIAndroidBridge.h"
 
 using namespace mozilla;
 
 jclass AndroidGeckoEvent::jGeckoEventClass = 0;
 jfieldID AndroidGeckoEvent::jActionField = 0;
 jfieldID AndroidGeckoEvent::jTypeField = 0;
+jfieldID AndroidGeckoEvent::jAckNeededField = 0;
 jfieldID AndroidGeckoEvent::jTimeField = 0;
 jfieldID AndroidGeckoEvent::jPoints = 0;
 jfieldID AndroidGeckoEvent::jPointIndicies = 0;
 jfieldID AndroidGeckoEvent::jPressures = 0;
 jfieldID AndroidGeckoEvent::jPointRadii = 0;
 jfieldID AndroidGeckoEvent::jOrientations = 0;
 jfieldID AndroidGeckoEvent::jXField = 0;
 jfieldID AndroidGeckoEvent::jYField = 0;
@@ -207,16 +208,17 @@ void
 AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
 {
     initInit();
 
     jGeckoEventClass = getClassGlobalRef("org/mozilla/gecko/GeckoEvent");
 
     jActionField = getField("mAction", "I");
     jTypeField = getField("mType", "I");
+    jAckNeededField = getField("mAckNeeded", "Z");
     jTimeField = getField("mTime", "J");
     jPoints = getField("mPoints", "[Landroid/graphics/Point;");
     jPointIndicies = getField("mPointIndicies", "[I");
     jOrientations = getField("mOrientations", "[F");
     jPressures = getField("mPressures", "[F");
     jPointRadii = getField("mPointRadii", "[Landroid/graphics/Point;");
     jXField = getField("mX", "D");
     jYField = getField("mY", "D");
@@ -526,16 +528,17 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jo
 
     wrapped_obj = jobj;
 
     if (!jobj)
         return;
 
     mAction = jenv->GetIntField(jobj, jActionField);
     mType = jenv->GetIntField(jobj, jTypeField);
+    mAckNeeded = jenv->GetBooleanField(jobj, jAckNeededField);
 
     switch (mType) {
         case SIZE_CHANGED:
             ReadPointArray(mPoints, jenv, jPoints, 2);
             break;
 
         case KEY_EVENT:
             mTime = jenv->GetLongField(jobj, jTimeField);
--- a/widget/android/AndroidJavaWrappers.h
+++ b/widget/android/AndroidJavaWrappers.h
@@ -652,16 +652,17 @@ public:
     void Init(int aType);
     void Init(int aType, int aAction);
     void Init(int x1, int y1, int x2, int y2);
     void Init(int aType, const nsIntRect &aRect);
     void Init(AndroidGeckoEvent *aResizeEvent);
 
     int Action() { return mAction; }
     int Type() { return mType; }
+    bool AckNeeded() { return mAckNeeded; }
     int64_t Time() { return mTime; }
     const nsTArray<nsIntPoint>& Points() { return mPoints; }
     const nsTArray<int>& PointIndicies() { return mPointIndicies; }
     const nsTArray<float>& Pressures() { return mPressures; }
     const nsTArray<float>& Orientations() { return mOrientations; }
     const nsTArray<nsIntPoint>& PointRadii() { return mPointRadii; }
     double X() { return mX; }
     double Y() { return mY; }
@@ -694,16 +695,17 @@ public:
     double Bandwidth() { return mBandwidth; }
     bool CanBeMetered() { return mCanBeMetered; }
     short ScreenOrientation() { return mScreenOrientation; }
     RefCountedJavaObject* ByteBuffer() { return mByteBuffer; }
 
 protected:
     int mAction;
     int mType;
+    bool mAckNeeded;
     int64_t mTime;
     nsTArray<nsIntPoint> mPoints;
     nsTArray<nsIntPoint> mPointRadii;
     nsTArray<int> mPointIndicies;
     nsTArray<float> mOrientations;
     nsTArray<float> mPressures;
     nsIntRect mRect;
     int mFlags, mMetaState;
@@ -738,16 +740,17 @@ protected:
                         int32_t count);
     void ReadRectField(JNIEnv *jenv);
     void ReadCharactersField(JNIEnv *jenv);
     void ReadCharactersExtraField(JNIEnv *jenv);
 
     static jclass jGeckoEventClass;
     static jfieldID jActionField;
     static jfieldID jTypeField;
+    static jfieldID jAckNeededField;
     static jfieldID jTimeField;
     static jfieldID jPoints;
     static jfieldID jPointIndicies;
     static jfieldID jOrientations;
     static jfieldID jPressures;
     static jfieldID jPointRadii;
     static jfieldID jXField;
     static jfieldID jYField;
@@ -794,17 +797,17 @@ public:
         DRAW = 7,
         SIZE_CHANGED = 8,
         ACTIVITY_STOPPING = 9,
         ACTIVITY_PAUSING = 10,
         ACTIVITY_SHUTDOWN = 11,
         LOAD_URI = 12,
         SURFACE_CREATED = 13,   // used by XUL fennec only
         SURFACE_DESTROYED = 14, // used by XUL fennec only
-        GECKO_EVENT_SYNC = 15,
+        NOOP = 15,
         FORCED_RESIZE = 16, // used internally in nsAppShell/nsWindow
         ACTIVITY_START = 17,
         BROADCAST = 19,
         VIEWPORT = 20,
         VISITED = 21,
         NETWORK_CHANGED = 22,
         ACTIVITY_RESUMING = 24,
         THUMBNAIL = 25,
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -554,18 +554,26 @@ nsAppShell::ProcessNextNativeEvent(bool 
         orientation =
             static_cast<dom::ScreenOrientation>(curEvent->ScreenOrientation());
 
         hal::NotifyScreenConfigurationChange(
             hal::ScreenConfiguration(rect, orientation, colorDepth, pixelDepth));
         break;
     }
 
+    case AndroidGeckoEvent::NOOP:
+        break;
+
     default:
         nsWindow::OnGlobalAndroidEvent(curEvent);
+        break;
+    }
+
+    if (curEvent->AckNeeded()) {
+        AndroidBridge::Bridge()->AcknowledgeEvent();
     }
 
     EVLOG("nsAppShell: -- done event %p %d", (void*)curEvent.get(), curEvent->Type());
 
     return true;
 }
 
 void
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -961,23 +961,16 @@ nsWindow::OnGlobalAndroidEvent(AndroidGe
             // flash.) This means it's now safe for layer updates to occur.
             // Since we might have prevented one or more draw events from
             // occurring while the compositor was paused, we need to schedule
             // a draw event now.
             if (!sCompositorPaused) {
                 win->RedrawAll();
             }
             break;
-
-        case AndroidGeckoEvent::GECKO_EVENT_SYNC:
-            AndroidBridge::Bridge()->AcknowledgeEventSync();
-            break;
-
-        default:
-            break;
     }
 }
 
 void
 nsWindow::OnAndroidEvent(AndroidGeckoEvent *ae)
 {
     if (!AndroidBridge::Bridge())
         return;