Bug 1415074 - Fix unresponsiveness after restoring GeckoView states; r=jchen

Fix a bug where GeckoView becomes unresponsive to dispatched events
after restoring states, due to the native queue not being restored.
r=me for small, tested patch.

MozReview-Commit-ID: K1cVjjNaZK1

--HG--
extra : rebase_source : b1329c84d82f5bdc06767bf310ca87e52ff6ec9b
This commit is contained in:
Jim Chen 2017-11-07 01:53:11 -05:00
parent c15f333a09
commit 832cd8d996
6 changed files with 115 additions and 18 deletions

View File

@ -71,6 +71,10 @@ public final class EventDispatcher extends JNIObject {
mNativeQueue = queue;
}
public NativeQueue getNativeQueue() {
return mNativeQueue;
}
private boolean isReadyForDispatchingToGecko() {
return mNativeQueue.isReady();
}

View File

@ -282,7 +282,7 @@ public class GeckoSession implements Parcelable {
private final Listener mListener = new Listener();
protected static final class Window extends JNIObject implements IInterface {
private final NativeQueue mNativeQueue;
private NativeQueue mNativeQueue;
private Binder mBinder;
public Window(final NativeQueue nativeQueue) {
@ -309,6 +309,18 @@ public class GeckoSession implements Parcelable {
@WrapForJNI(dispatchTo = "proxy")
native void close();
@WrapForJNI(dispatchTo = "proxy")
native void transfer(EventDispatcher dispatcher, GeckoBundle settings);
@WrapForJNI(calledFrom = "gecko")
private synchronized void onTransfer(final EventDispatcher dispatcher) {
final NativeQueue nativeQueue = dispatcher.getNativeQueue();
if (mNativeQueue != nativeQueue) {
nativeQueue.setState(mNativeQueue.getState());
mNativeQueue = nativeQueue;
}
}
@WrapForJNI(dispatchTo = "proxy")
native void attach(GeckoView view, Object compositor);
@ -358,13 +370,28 @@ public class GeckoSession implements Parcelable {
mListener.registerListeners();
}
/* package */ void transferFrom(final GeckoSession session) {
private void transferFrom(final Window window, final GeckoSessionSettings settings) {
if (isOpen()) {
throw new IllegalStateException("Session is open");
}
mWindow = session.mWindow;
mSettings = new GeckoSessionSettings(session.mSettings, this);
mWindow = window;
mSettings = new GeckoSessionSettings(settings, this);
if (mWindow != null) {
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
mWindow.transfer(mEventDispatcher, mSettings.asBundle());
} else {
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
mWindow, "transfer",
EventDispatcher.class, mEventDispatcher,
GeckoBundle.class, mSettings.asBundle());
}
}
}
/* package */ void transferFrom(final GeckoSession session) {
transferFrom(session.mWindow, session.mSettings);
session.mWindow = null;
}
@ -381,22 +408,13 @@ public class GeckoSession implements Parcelable {
// AIDL code may call readFromParcel even though it's not part of Parcelable.
public void readFromParcel(final Parcel source) {
if (isOpen()) {
throw new IllegalStateException("Session is open");
}
final IBinder binder = source.readStrongBinder();
final IInterface window = (binder != null) ?
final IInterface ifce = (binder != null) ?
binder.queryLocalInterface(Window.class.getName()) : null;
if (window instanceof Window) {
mWindow = (Window) window;
} else {
mWindow = null;
}
final Window window = (ifce instanceof Window) ? (Window) ifce : null;
final GeckoSessionSettings settings =
source.readParcelable(getClass().getClassLoader());
mSettings = new GeckoSessionSettings(settings, this);
transferFrom(window, settings);
}
public static final Creator<GeckoSession> CREATOR = new Creator<GeckoSession>() {

View File

@ -222,7 +222,7 @@ template<class Impl>
class GeckoSession::Window::Natives : public mozilla::jni::NativeImpl<Window, Impl>
{
public:
static const JNINativeMethod methods[4];
static const JNINativeMethod methods[5];
};
template<class Impl>
@ -242,7 +242,11 @@ const JNINativeMethod GeckoSession::Window::Natives<Impl>::methods[] = {
mozilla::jni::MakeNativeMethod<GeckoSession::Window::Open_t>(
mozilla::jni::NativeStub<GeckoSession::Window::Open_t, Impl>
::template Wrap<&Impl::Open>)
::template Wrap<&Impl::Open>),
mozilla::jni::MakeNativeMethod<GeckoSession::Window::Transfer_t>(
mozilla::jni::NativeStub<GeckoSession::Window::Transfer_t, Impl>
::template Wrap<&Impl::Transfer>)
};
template<class Impl>

View File

@ -792,9 +792,20 @@ auto GeckoSession::Window::OnReady() const -> void
return mozilla::jni::Method<OnReady_t>::Call(Window::mCtx, nullptr);
}
constexpr char GeckoSession::Window::OnTransfer_t::name[];
constexpr char GeckoSession::Window::OnTransfer_t::signature[];
auto GeckoSession::Window::OnTransfer(mozilla::jni::Object::Param a0) const -> void
{
return mozilla::jni::Method<OnTransfer_t>::Call(Window::mCtx, nullptr, a0);
}
constexpr char GeckoSession::Window::Open_t::name[];
constexpr char GeckoSession::Window::Open_t::signature[];
constexpr char GeckoSession::Window::Transfer_t::name[];
constexpr char GeckoSession::Window::Transfer_t::signature[];
const char GeckoThread::name[] =
"org/mozilla/gecko/GeckoThread";

View File

@ -2420,6 +2420,26 @@ public:
auto OnReady() const -> void;
struct OnTransfer_t {
typedef Window Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<
mozilla::jni::Object::Param> Args;
static constexpr char name[] = "onTransfer";
static constexpr char signature[] =
"(Lorg/mozilla/gecko/EventDispatcher;)V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::CURRENT;
};
auto OnTransfer(mozilla::jni::Object::Param) const -> void;
struct Open_t {
typedef Window Owner;
typedef void ReturnType;
@ -2443,6 +2463,25 @@ public:
mozilla::jni::DispatchTarget::PROXY;
};
struct Transfer_t {
typedef Window Owner;
typedef void ReturnType;
typedef void SetterType;
typedef mozilla::jni::Args<
mozilla::jni::Object::Param,
mozilla::jni::Object::Param> Args;
static constexpr char name[] = "transfer";
static constexpr char signature[] =
"(Lorg/mozilla/gecko/EventDispatcher;Lorg/mozilla/gecko/util/GeckoBundle;)V";
static const bool isStatic = false;
static const mozilla::jni::ExceptionMode exceptionMode =
mozilla::jni::ExceptionMode::ABORT;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;
static const mozilla::jni::DispatchTarget dispatchTarget =
mozilla::jni::DispatchTarget::PROXY;
};
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::ANY;

View File

@ -288,6 +288,11 @@ public:
// Close and destroy the nsWindow.
void Close();
// Transfer this nsWindow to new GeckoSession objects.
void Transfer(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aDispatcher,
jni::Object::Param aSettings);
// Reattach this nsWindow to a new GeckoView.
void Attach(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aView, jni::Object::Param aCompositor);
@ -1353,6 +1358,22 @@ nsWindow::GeckoViewSupport::Close()
mGeckoViewWindow = nullptr;
}
void
nsWindow::GeckoViewSupport::Transfer(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aDispatcher,
jni::Object::Param aSettings)
{
if (!window.mAndroidView) {
return;
}
window.mAndroidView->mEventDispatcher->Attach(
java::EventDispatcher::Ref::From(aDispatcher), mDOMWindow);
window.mAndroidView->mSettings = java::GeckoBundle::Ref::From(aSettings);
inst->OnTransfer(aDispatcher);
}
void
nsWindow::GeckoViewSupport::Attach(const GeckoSession::Window::LocalRef& inst,
jni::Object::Param aView,