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
--- 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;
+ }
}