зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1352534 - [1.3] Allow for mupltiple native queues and assign a unique queue per GeckoView. r=jchen
This commit is contained in:
Родитель
75452c87a4
Коммит
2b30df194c
|
@ -9,7 +9,6 @@ import org.mozilla.gecko.annotation.RobocopTarget;
|
|||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.mozglue.JNIObject;
|
||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
|
@ -55,7 +54,7 @@ public final class EventDispatcher extends JNIObject {
|
|||
new HashMap<String, List<BundleEventListener>>(DEFAULT_BACKGROUND_EVENTS_COUNT);
|
||||
|
||||
private boolean mAttachedToGecko;
|
||||
private volatile StateHolder mStateHolder;
|
||||
private final NativeQueue mNativeQueue;
|
||||
|
||||
@ReflectionTarget
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
|
@ -64,22 +63,15 @@ public final class EventDispatcher extends JNIObject {
|
|||
}
|
||||
|
||||
/* package */ EventDispatcher() {
|
||||
mStateHolder = GeckoThread.getStateHolder();
|
||||
mNativeQueue = GeckoThread.getNativeQueue();
|
||||
}
|
||||
|
||||
/* package */ EventDispatcher(final NativeQueue.StateHolder stateHolder) {
|
||||
mStateHolder = stateHolder;
|
||||
}
|
||||
|
||||
/* package */ void setStateHolder(final NativeQueue.StateHolder stateHolder) {
|
||||
mStateHolder = stateHolder;
|
||||
// Force queue flushing.
|
||||
final NativeQueue.State state = mStateHolder.getState();
|
||||
mStateHolder.checkAndSetState(state, state);
|
||||
/* package */ EventDispatcher(final NativeQueue queue) {
|
||||
mNativeQueue = queue;
|
||||
}
|
||||
|
||||
private boolean isReadyForDispatchingToGecko() {
|
||||
return mStateHolder.isReady();
|
||||
return mNativeQueue.isReady();
|
||||
}
|
||||
|
||||
@WrapForJNI(dispatchTo = "gecko") @Override // JNIObject
|
||||
|
@ -301,8 +293,7 @@ public final class EventDispatcher extends JNIObject {
|
|||
// Gecko, we make a special exception to queue this event until
|
||||
// Gecko(View) is ready. This way, Gecko can first register its
|
||||
// listeners, and accept the event when it is ready.
|
||||
NativeQueue.queueUntil(mStateHolder,
|
||||
mStateHolder.getReadyState(), this, "dispatchToGecko",
|
||||
mNativeQueue.queueUntilReady(this, "dispatchToGecko",
|
||||
String.class, type,
|
||||
GeckoBundle.class, message,
|
||||
EventCallback.class, JavaCallbackDelegate.wrap(callback));
|
||||
|
|
|
@ -8,7 +8,6 @@ package org.mozilla.gecko;
|
|||
import org.mozilla.gecko.annotation.RobocopTarget;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.mozglue.GeckoLoader;
|
||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
||||
import org.mozilla.gecko.util.FileUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
|
@ -80,11 +79,11 @@ public class GeckoThread extends Thread {
|
|||
}
|
||||
}
|
||||
|
||||
private static final StateHolder sStateHolder =
|
||||
new StateHolder(State.INITIAL, State.RUNNING);
|
||||
private static final NativeQueue sNativeQueue =
|
||||
new NativeQueue(State.INITIAL, State.RUNNING);
|
||||
|
||||
/* package */ static StateHolder getStateHolder() {
|
||||
return sStateHolder;
|
||||
/* package */ static NativeQueue getNativeQueue() {
|
||||
return sNativeQueue;
|
||||
}
|
||||
|
||||
public static final State MIN_STATE = State.INITIAL;
|
||||
|
@ -446,7 +445,7 @@ public class GeckoThread extends Thread {
|
|||
* @return True if the current Gecko thread state matches
|
||||
*/
|
||||
public static boolean isState(final State state) {
|
||||
return sStateHolder.getState().is(state);
|
||||
return sNativeQueue.getState().is(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -457,7 +456,7 @@ public class GeckoThread extends Thread {
|
|||
* @return True if the current Gecko thread state matches
|
||||
*/
|
||||
public static boolean isStateAtLeast(final State state) {
|
||||
return sStateHolder.getState().isAtLeast(state);
|
||||
return sNativeQueue.getState().isAtLeast(state);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,7 +467,7 @@ public class GeckoThread extends Thread {
|
|||
* @return True if the current Gecko thread state matches
|
||||
*/
|
||||
public static boolean isStateAtMost(final State state) {
|
||||
return state.isAtLeast(sStateHolder.getState());
|
||||
return state.isAtLeast(sNativeQueue.getState());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -485,13 +484,13 @@ public class GeckoThread extends Thread {
|
|||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private static void setState(final State newState) {
|
||||
sStateHolder.setState(newState);
|
||||
sNativeQueue.setState(newState);
|
||||
}
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private static boolean checkAndSetState(final State expectedState,
|
||||
final State newState) {
|
||||
return sStateHolder.checkAndSetState(expectedState, newState);
|
||||
return sNativeQueue.checkAndSetState(expectedState, newState);
|
||||
}
|
||||
|
||||
@WrapForJNI(stubName = "SpeculativeConnect")
|
||||
|
@ -561,7 +560,7 @@ public class GeckoThread extends Thread {
|
|||
*/
|
||||
public static void queueNativeCall(final Class<?> cls, final String methodName,
|
||||
final Object... args) {
|
||||
NativeQueue.queueUntil(getStateHolder(), State.RUNNING, cls, methodName, args);
|
||||
sNativeQueue.queueUntilReady(cls, methodName, args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -569,7 +568,7 @@ public class GeckoThread extends Thread {
|
|||
*/
|
||||
public static void queueNativeCall(final Object obj, final String methodName,
|
||||
final Object... args) {
|
||||
NativeQueue.queueUntil(getStateHolder(), State.RUNNING, obj, methodName, args);
|
||||
sNativeQueue.queueUntilReady(obj, methodName, args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -577,7 +576,7 @@ public class GeckoThread extends Thread {
|
|||
*/
|
||||
public static void queueNativeCallUntil(final State state, final Object obj, final String methodName,
|
||||
final Object... args) {
|
||||
NativeQueue.queueUntil(getStateHolder(), state, obj, methodName, args);
|
||||
sNativeQueue.queueUntil(state, obj, methodName, args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -585,6 +584,6 @@ public class GeckoThread extends Thread {
|
|||
*/
|
||||
public static void queueNativeCallUntil(final State state, final Class<?> cls, final String methodName,
|
||||
final Object... args) {
|
||||
NativeQueue.queueUntil(getStateHolder(), state, cls, methodName, args);
|
||||
sNativeQueue.queueUntil(state, cls, methodName, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.mozilla.gecko.annotation.ReflectionTarget;
|
|||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.mozglue.JNIObject;
|
||||
import org.mozilla.gecko.NativeQueue.StateHolder;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
|
@ -47,7 +46,7 @@ public class GeckoView extends LayerView
|
|||
@WrapForJNI INITIAL(0),
|
||||
@WrapForJNI READY(1);
|
||||
|
||||
private int mRank;
|
||||
private final int mRank;
|
||||
|
||||
private State(int rank) {
|
||||
mRank = rank;
|
||||
|
@ -60,18 +59,16 @@ public class GeckoView extends LayerView
|
|||
|
||||
@Override
|
||||
public boolean isAtLeast(final NativeQueue.State other) {
|
||||
if (other instanceof State) {
|
||||
return mRank >= ((State) other).mRank;
|
||||
}
|
||||
return false;
|
||||
return (other instanceof State) &&
|
||||
mRank >= ((State) other).mRank;
|
||||
}
|
||||
}
|
||||
|
||||
private static final StateHolder sDummyStateHolder =
|
||||
new StateHolder(State.INITIAL, State.READY);
|
||||
private final NativeQueue mNativeQueue =
|
||||
new NativeQueue(State.INITIAL, State.READY);
|
||||
|
||||
private final EventDispatcher mEventDispatcher =
|
||||
new EventDispatcher(sDummyStateHolder);
|
||||
new EventDispatcher(mNativeQueue);
|
||||
|
||||
private ChromeDelegate mChromeDelegate;
|
||||
/* package */ ContentListener mContentListener;
|
||||
|
@ -88,11 +85,12 @@ public class GeckoView extends LayerView
|
|||
@WrapForJNI(dispatchTo = "proxy")
|
||||
protected static final class Window extends JNIObject {
|
||||
@WrapForJNI(skip = true)
|
||||
/* package */ final StateHolder mStateHolder =
|
||||
new StateHolder(State.INITIAL, State.READY);
|
||||
/* package */ NativeQueue mNativeQueue;
|
||||
|
||||
@WrapForJNI(skip = true)
|
||||
/* package */ Window() {}
|
||||
/* package */ Window(final NativeQueue queue) {
|
||||
mNativeQueue = queue;
|
||||
}
|
||||
|
||||
static native void open(Window instance, GeckoView view,
|
||||
Object compositor, EventDispatcher dispatcher,
|
||||
|
@ -109,8 +107,8 @@ public class GeckoView extends LayerView
|
|||
native void loadUri(String uri, int flags);
|
||||
|
||||
@WrapForJNI(calledFrom = "gecko")
|
||||
private void setState(final State newState) {
|
||||
mStateHolder.setState(newState);
|
||||
private synchronized void setState(final State newState) {
|
||||
mNativeQueue.setState(newState);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,7 +285,12 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
protected void reattachWindow() {
|
||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
||||
synchronized (mWindow) {
|
||||
if (mNativeQueue != mWindow.mNativeQueue) {
|
||||
mNativeQueue.setState(mWindow.mNativeQueue.getState());
|
||||
mWindow.mNativeQueue = mNativeQueue;
|
||||
}
|
||||
}
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
mWindow.reattach(this, getCompositor(), mEventDispatcher);
|
||||
|
@ -304,8 +307,7 @@ public class GeckoView extends LayerView
|
|||
|
||||
if (mWindow == null) {
|
||||
// Open a new nsWindow if we didn't have one from before.
|
||||
mWindow = new Window();
|
||||
mEventDispatcher.setStateHolder(mWindow.mStateHolder);
|
||||
mWindow = new Window(mNativeQueue);
|
||||
openWindow();
|
||||
} else {
|
||||
reattachWindow();
|
||||
|
@ -336,7 +338,6 @@ public class GeckoView extends LayerView
|
|||
mWindow, "disposeNative");
|
||||
}
|
||||
|
||||
mEventDispatcher.setStateHolder(sDummyStateHolder);
|
||||
mOnAttachedToWindowCalled = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,42 +20,34 @@ public class NativeQueue {
|
|||
boolean isAtLeast(final State other);
|
||||
}
|
||||
|
||||
public static class StateHolder {
|
||||
private volatile State mState;
|
||||
private final State mReadyState;
|
||||
private volatile State mState;
|
||||
private final State mReadyState;
|
||||
|
||||
public StateHolder(final State initial, final State ready) {
|
||||
this.mState = initial;
|
||||
this.mReadyState = ready;
|
||||
}
|
||||
public NativeQueue(final State initial, final State ready) {
|
||||
mState = initial;
|
||||
mReadyState = ready;
|
||||
}
|
||||
|
||||
public boolean isReady() {
|
||||
return getState().isAtLeast(mReadyState);
|
||||
}
|
||||
public boolean isReady() {
|
||||
return getState().isAtLeast(mReadyState);
|
||||
}
|
||||
|
||||
public State getReadyState() {
|
||||
return mReadyState;
|
||||
}
|
||||
public State getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return mState;
|
||||
}
|
||||
public boolean setState(final State newState) {
|
||||
return checkAndSetState(null, newState);
|
||||
}
|
||||
|
||||
public boolean setState(final State newState) {
|
||||
return checkAndSetState(null, newState);
|
||||
}
|
||||
|
||||
public boolean checkAndSetState(final State expectedState,
|
||||
final State newState) {
|
||||
synchronized (NativeQueue.sQueue) {
|
||||
if (expectedState != null && !mState.is(expectedState)) {
|
||||
return false;
|
||||
}
|
||||
NativeQueue.flushQueuedLocked(newState);
|
||||
mState = newState;
|
||||
return true;
|
||||
}
|
||||
public synchronized boolean checkAndSetState(final State expectedState,
|
||||
final State newState) {
|
||||
if (expectedState != null && !mState.is(expectedState)) {
|
||||
return false;
|
||||
}
|
||||
flushQueuedLocked(newState);
|
||||
mState = newState;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class QueuedCall {
|
||||
|
@ -74,7 +66,7 @@ public class NativeQueue {
|
|||
}
|
||||
|
||||
private static final int QUEUED_CALLS_COUNT = 16;
|
||||
/* package */ static final ArrayList<QueuedCall> sQueue =
|
||||
/* package */ final ArrayList<QueuedCall> mQueue =
|
||||
new ArrayList<>(QUEUED_CALLS_COUNT);
|
||||
|
||||
// Invoke the given Method and handle checked Exceptions.
|
||||
|
@ -91,12 +83,11 @@ public class NativeQueue {
|
|||
}
|
||||
|
||||
// Queue a call to the given method.
|
||||
private static void queueNativeCallLocked(final StateHolder stateHolder,
|
||||
final Class<?> cls,
|
||||
final String methodName,
|
||||
final Object obj,
|
||||
final Object[] args,
|
||||
final State state) {
|
||||
private void queueNativeCallLocked(final Class<?> cls,
|
||||
final String methodName,
|
||||
final Object obj,
|
||||
final Object[] args,
|
||||
final State state) {
|
||||
final ArrayList<Class<?>> argTypes = new ArrayList<>(args.length);
|
||||
final ArrayList<Object> argValues = new ArrayList<>(args.length);
|
||||
|
||||
|
@ -135,63 +126,82 @@ public class NativeQueue {
|
|||
throw new UnsupportedOperationException("Not allowed to queue non-native methods");
|
||||
}
|
||||
|
||||
if (stateHolder.getState().isAtLeast(state)) {
|
||||
if (getState().isAtLeast(state)) {
|
||||
invokeMethod(method, obj, argValues.toArray());
|
||||
return;
|
||||
}
|
||||
|
||||
sQueue.add(new QueuedCall(
|
||||
mQueue.add(new QueuedCall(
|
||||
method, obj, argValues.toArray(), state));
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a call to the given instance method if the given current state does
|
||||
* not satisfy the isReady condition.
|
||||
*
|
||||
* @param obj Object that declares the instance method.
|
||||
* @param methodName Name of the instance method.
|
||||
* @param args Args to call the instance method with; to specify a parameter
|
||||
* type, pass in a Class instance first, followed by the value.
|
||||
*/
|
||||
public synchronized void queueUntilReady(final Object obj,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
queueNativeCallLocked(obj.getClass(), methodName, obj, args, mReadyState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a call to the given static method if the given current state does
|
||||
* not satisfy the isReady condition.
|
||||
*
|
||||
* @param cls Class that declares the static method.
|
||||
* @param methodName Name of the instance method.
|
||||
* @param args Args to call the instance method with; to specify a parameter
|
||||
* type, pass in a Class instance first, followed by the value.
|
||||
*/
|
||||
public synchronized void queueUntilReady(final Class<?> cls,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
queueNativeCallLocked(cls, methodName, null, args, mReadyState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a call to the given instance method if the given current state does
|
||||
* not satisfy the given state.
|
||||
*
|
||||
* @param stateHolder The state holder used to query the current state.
|
||||
* @param state The state in which the native call could be executed.
|
||||
* @param obj Object that declares the instance method.
|
||||
* @param methodName Name of the instance method.
|
||||
* @param args Args to call the instance method with; to specify a parameter
|
||||
* type, pass in a Class instance first, followed by the value.
|
||||
*/
|
||||
public static void queueUntil(final StateHolder stateHolder,
|
||||
final State state,
|
||||
final Object obj,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
synchronized (sQueue) {
|
||||
queueNativeCallLocked(stateHolder, obj.getClass(), methodName, obj,
|
||||
args, state);
|
||||
}
|
||||
public synchronized void queueUntil(final State state, final Object obj,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
queueNativeCallLocked(obj.getClass(), methodName, obj, args, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a call to the given static method if the given current state does
|
||||
* not satisfy the given state.
|
||||
*
|
||||
* @param stateHolder The state holder used to query the current state.
|
||||
* @param state The state in which the native call could be executed.
|
||||
* @param cls Class that declares the static method.
|
||||
* @param methodName Name of the instance method.
|
||||
* @param args Args to call the instance method with; to specify a parameter
|
||||
* type, pass in a Class instance first, followed by the value.
|
||||
*/
|
||||
public static void queueUntil(final StateHolder stateHolder,
|
||||
final State state,
|
||||
final Class<?> cls,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
synchronized (sQueue) {
|
||||
queueNativeCallLocked(stateHolder, cls, methodName, null, args, state);
|
||||
}
|
||||
public synchronized void queueUntil(final State state, final Class<?> cls,
|
||||
final String methodName,
|
||||
final Object... args) {
|
||||
queueNativeCallLocked(cls, methodName, null, args, state);
|
||||
}
|
||||
|
||||
// Run all queued methods
|
||||
private static void flushQueuedLocked(final State state) {
|
||||
private void flushQueuedLocked(final State state) {
|
||||
int lastSkipped = -1;
|
||||
for (int i = 0; i < sQueue.size(); i++) {
|
||||
final QueuedCall call = sQueue.get(i);
|
||||
for (int i = 0; i < mQueue.size(); i++) {
|
||||
final QueuedCall call = mQueue.get(i);
|
||||
if (call == null) {
|
||||
// We already handled the call.
|
||||
continue;
|
||||
|
@ -202,18 +212,18 @@ public class NativeQueue {
|
|||
continue;
|
||||
}
|
||||
// Mark as handled.
|
||||
sQueue.set(i, null);
|
||||
mQueue.set(i, null);
|
||||
|
||||
invokeMethod(call.method, call.target, call.args);
|
||||
}
|
||||
if (lastSkipped < 0) {
|
||||
// We're done here; release the memory
|
||||
sQueue.clear();
|
||||
sQueue.trimToSize();
|
||||
} else if (lastSkipped < sQueue.size() - 1) {
|
||||
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.
|
||||
sQueue.subList(lastSkipped + 1, sQueue.size()).clear();
|
||||
mQueue.subList(lastSkipped + 1, mQueue.size()).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче