Bug 1431201 - Clear native queue when disposing window; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Wed, 24 Jan 2018 10:39:49 -0500
changeset 724141 5017ff2e848ad6d5d016e61687febba9ad06e665
parent 723473 e2bb11b88bd45bdb2e055042e1624b74d414e73c
child 747069 b658707a96c48b3ad8f8cc5172cad47ccd13909d
push id96662
push userbmo:nchen@mozilla.com
push dateWed, 24 Jan 2018 15:40:17 +0000
reviewerssnorp
bugs1431201
milestone60.0a1
Bug 1431201 - Clear native queue when disposing window; r?snorp 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;
+    }
 }