Bug 1431201 - Clear native queue when disposing window; r=snorp a=lizzard
authorJim Chen <nchen@mozilla.com>
Wed, 24 Jan 2018 10:39:49 -0500
changeset 454591 8292d441cb0cf8aafbb8f9555237ac26deafd09d
parent 454590 b54898c488ddb7687cbda2bfc01cac1087837f35
child 454592 a88fde4219d956f6ead8bcbd4678186cedcd0564
push id1648
push usermtabara@mozilla.com
push dateThu, 01 Mar 2018 12:45:47 +0000
treeherdermozilla-release@cbb9688c2eeb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, lizzard
bugs1431201
milestone59.0
Bug 1431201 - Clear native queue when disposing window; r=snorp a=lizzard Dispose the native call queue when disposing a window object, so we don't end up with stale calls in the queue that can cause crashes. MozReview-Commit-ID: J1HNOXKAX6E
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/NativeQueue.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoSession.java
@@ -311,16 +311,21 @@ public class GeckoSession extends LayerS
                                        int screenId, boolean privateMode);
 
         @Override // JNIObject
         protected void disposeNative() {
             // Detach ourselves from the binder as well, to prevent this window from being
             // read from any parcels.
             asBinder().attachInterface(null, Window.class.getName());
 
+            // Reset our queue, so we don't end up with queued calls on a disposed object.
+            synchronized (this) {
+                mNativeQueue.reset(State.INITIAL);
+            }
+
             if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
                 nativeDisposeNative();
             } else {
                 GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
                         this, "nativeDisposeNative");
             }
         }
 
@@ -337,17 +342,17 @@ public class GeckoSession extends LayerS
         @WrapForJNI(calledFrom = "gecko")
         private synchronized void onTransfer(final EventDispatcher dispatcher) {
             final NativeQueue nativeQueue = dispatcher.getNativeQueue();
             if (mNativeQueue != nativeQueue) {
                 // Set new queue to the same state as the old queue,
                 // then return the old queue to its initial state if applicable,
                 // because the old queue is no longer the active queue.
                 nativeQueue.setState(mNativeQueue.getState());
-                mNativeQueue.checkAndSetState(State.READY, State.INITIAL);
+                mNativeQueue.reset(State.INITIAL);
                 mNativeQueue = nativeQueue;
             }
         }
 
         @WrapForJNI(dispatchTo = "proxy")
         public native void attachEditable(IGeckoEditableParent parent,
                                           GeckoEditableChild child);
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/NativeQueue.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/NativeQueue.java
@@ -215,16 +215,20 @@ public class NativeQueue {
             // Mark as handled.
             mQueue.set(i, null);
 
             invokeMethod(call.method, call.target, call.args);
         }
         if (lastSkipped < 0) {
             // We're done here; release the memory
             mQueue.clear();
-            mQueue.trimToSize();
         } else if (lastSkipped < mQueue.size() - 1) {
             // We skipped some; free up null entries at the end,
             // but keep all the previous entries for later.
             mQueue.subList(lastSkipped + 1, mQueue.size()).clear();
         }
     }
+
+    public synchronized void reset(final State initial) {
+        mQueue.clear();
+        mState = initial;
+    }
 }