Bug 1458327 - 1. Pass init-data instead of settings to Window; r=esawin
authorJim Chen <nchen@mozilla.com>
Fri, 04 May 2018 21:08:10 -0400
changeset 473112 7a9d7817a640aeec9a48eb37063b6a5c6e7e422b
parent 473111 a5832837830da61ee3ccd851d068b28a36951b0b
child 473113 f37d7d18d8e740bbb6d556385e94fa884719c217
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin
bugs1458327
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1458327 - 1. Pass init-data instead of settings to Window; r=esawin Instead of passing a live settings object to the native Window, pass a static initialization data bundle to the Window. The bundle contains settings at the time of creation. All changes to settings after creation are updated through events, rather than the live object. Using a live object between Gecko and UI threads has some drawbacks, including the need to lock the object, and the fact it won't work with remote runtimes across processes. MozReview-Commit-ID: 1DngLfJ0Fnc
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java
widget/android/EventDispatcher.cpp
widget/android/nsIAndroidBridge.idl
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -498,17 +498,17 @@ public class GeckoSession extends LayerS
             }
             return mBinder;
         }
 
         // Create a new Gecko window and assign an initial set of Java session objects to it.
         @WrapForJNI(dispatchTo = "proxy")
         public static native void open(Window instance, NativeQueue queue,
                                        Compositor compositor, EventDispatcher dispatcher,
-                                       GeckoBundle settings, String id, String chromeUri,
+                                       GeckoBundle initData, String id, String chromeUri,
                                        int screenId, boolean privateMode);
 
         @Override // JNIObject
         public void disposeNative() {
             if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
                 nativeDisposeNative();
             } else {
                 GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
@@ -546,44 +546,44 @@ public class GeckoSession extends LayerS
         @WrapForJNI(dispatchTo = "proxy", stubName = "Close")
         private native void nativeClose();
 
         // Assign a new set of Java session objects to the underlying Gecko window.
         // This replaces previously assigned objects from open() or transfer() calls.
         public synchronized void transfer(final NativeQueue queue,
                                           final Compositor compositor,
                                           final EventDispatcher dispatcher,
-                                          final GeckoBundle settings) {
+                                          final GeckoBundle initData) {
             if (mNativeQueue == null) {
                 // Already closed.
                 return;
             }
 
             if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
-                nativeTransfer(queue, compositor, dispatcher, settings);
+                nativeTransfer(queue, compositor, dispatcher, initData);
             } else {
                 GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
                         this, "nativeTransfer",
                         NativeQueue.class, queue,
                         Compositor.class, compositor,
                         EventDispatcher.class, dispatcher,
-                        GeckoBundle.class, settings);
+                        GeckoBundle.class, initData);
             }
 
             if (mNativeQueue != queue) {
                 // Reset the old queue to prevent old events from affecting this window.
                 // Gecko will call onReady later with the new queue if needed.
                 mNativeQueue.reset(State.INITIAL);
                 mNativeQueue = queue;
             }
         }
 
         @WrapForJNI(dispatchTo = "proxy", stubName = "Transfer")
         private native void nativeTransfer(NativeQueue queue, Compositor compositor,
-                                           EventDispatcher dispatcher, GeckoBundle settings);
+                                           EventDispatcher dispatcher, GeckoBundle initData);
 
         @WrapForJNI(dispatchTo = "proxy")
         public native void attachEditable(IGeckoEditableParent parent,
                                           GeckoEditableChild child);
 
         @WrapForJNI(calledFrom = "gecko")
         private synchronized void onReady(final @Nullable NativeQueue queue) {
             // onReady is called the first time the Gecko window is ready, with a null queue
@@ -662,17 +662,17 @@ public class GeckoSession extends LayerS
         }
 
         mWindow = window;
         mSettings = new GeckoSessionSettings(settings, this);
         mId = id;
 
         if (mWindow != null) {
             mWindow.transfer(mNativeQueue, mCompositor,
-                             mEventDispatcher, mSettings.asBundle());
+                             mEventDispatcher, createInitData());
 
             onWindowChanged(WINDOW_TRANSFER_IN, /* inProgress */ false);
         }
     }
 
     /* package */ void transferFrom(final GeckoSession session) {
         final boolean changing = (session.mWindow != null);
         if (changing) {
@@ -728,16 +728,22 @@ public class GeckoSession extends LayerS
     public boolean isOpen() {
         return mWindow != null;
     }
 
     /* package */ boolean isReady() {
         return mNativeQueue.isReady();
     }
 
+    private GeckoBundle createInitData() {
+        final GeckoBundle initData = new GeckoBundle(1);
+        initData.putBundle("settings", mSettings.toBundle());
+        return initData;
+    }
+
     /**
      * Opens the session.
      *
      * The session is in a 'closed' state when first created. Opening it creates
      * the underlying Gecko objects necessary to load a page, etc. Most GeckoSession
      * methods only take affect on an open session, and are queued until the session
      * is opened here. Opening a session is an asynchronous operation. You can check
      * the current state via isOpen().
@@ -762,26 +768,26 @@ public class GeckoSession extends LayerS
         final boolean isPrivate = mSettings.getBoolean(GeckoSessionSettings.USE_PRIVATE_MODE);
 
         mWindow = new Window(runtime, mNativeQueue);
 
         onWindowChanged(WINDOW_OPEN, /* inProgress */ true);
 
         if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
             Window.open(mWindow, mNativeQueue, mCompositor, mEventDispatcher,
-                        mSettings.asBundle(), mId, chromeUri, screenId, isPrivate);
+                        createInitData(), mId, chromeUri, screenId, isPrivate);
         } else {
             GeckoThread.queueNativeCallUntil(
                 GeckoThread.State.PROFILE_READY,
                 Window.class, "open",
                 Window.class, mWindow,
                 NativeQueue.class, mNativeQueue,
                 Compositor.class, mCompositor,
                 EventDispatcher.class, mEventDispatcher,
-                GeckoBundle.class, mSettings.asBundle(),
+                GeckoBundle.class, createInitData(),
                 String.class, mId,
                 String.class, chromeUri,
                 screenId, isPrivate);
         }
 
         onWindowChanged(WINDOW_OPEN, /* inProgress */ false);
     }
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSessionSettings.java
@@ -160,18 +160,18 @@ public final class GeckoSessionSettings 
     }
 
     public String getString(final Key<String> key) {
         synchronized (mBundle) {
             return mBundle.getString(key.name);
         }
     }
 
-    /* package */ GeckoBundle asBundle() {
-        return mBundle;
+    /* package */ GeckoBundle toBundle() {
+        return new GeckoBundle(mBundle);
     }
 
     @Override
     public String toString() {
         return mBundle.toString();
     }
 
     @Override
--- a/widget/android/EventDispatcher.cpp
+++ b/widget/android/EventDispatcher.cpp
@@ -820,16 +820,23 @@ EventDispatcher::Dispatch(const char16_t
                           java::GeckoBundle::Param aData,
                           nsIAndroidEventCallback* aCallback)
 {
     nsDependentString event(aEvent);
 
     ListenersList* list = mListenersMap.Get(event);
     if (list) {
         dom::AutoJSAPI jsapi;
+        if (mDOMWindow) {
+            NS_ENSURE_TRUE(jsapi.Init(mDOMWindow->GetCurrentInnerWindow()),
+                           NS_ERROR_FAILURE);
+        } else {
+            NS_ENSURE_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()),
+                           NS_ERROR_FAILURE);
+        }
         JS::RootedValue data(jsapi.cx());
         nsresult rv = UnboxData(/* Event */ nullptr, jsapi.cx(), aData, &data,
                                 /* BundleOnly */ true);
         NS_ENSURE_SUCCESS(rv, rv);
         return DispatchOnGecko(list, event, data, aCallback);
     }
 
     if (!mDispatcher) {
--- a/widget/android/nsIAndroidBridge.idl
+++ b/widget/android/nsIAndroidBridge.idl
@@ -66,17 +66,17 @@ interface nsIAndroidEventDispatcher : ns
   [implicit_jscontext]
   void unregisterListener(in nsIAndroidEventListener listener,
                           in jsval events);
 };
 
 [scriptable, uuid(60a78a94-6117-432f-9d49-304913a931c5)]
 interface nsIAndroidView : nsIAndroidEventDispatcher
 {
-  [implicit_jscontext] readonly attribute jsval settings;
+  [implicit_jscontext] readonly attribute jsval initData;
 };
 
 [scriptable, uuid(1beb70d3-70f3-4742-98cc-a3d301b26c0c)]
 interface nsIAndroidBridge : nsIAndroidEventDispatcher
 {
   attribute nsIAndroidBrowserApp browserApp;
   void contentDocumentChanged(in mozIDOMWindowProxy window);
   boolean isContentDocumentDisplayed(in mozIDOMWindowProxy window);
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -279,31 +279,31 @@ private:
 
 public:
     // Create and attach a window.
     static void Open(const jni::Class::LocalRef& aCls,
                      GeckoSession::Window::Param aWindow,
                      jni::Object::Param aQueue,
                      jni::Object::Param aCompositor,
                      jni::Object::Param aDispatcher,
-                     jni::Object::Param aSettings,
+                     jni::Object::Param aInitData,
                      jni::String::Param aId,
                      jni::String::Param aChromeURI,
                      int32_t aScreenId,
                      bool aPrivateMode);
 
     // Close and destroy the nsWindow.
     void Close();
 
     // Transfer this nsWindow to new GeckoSession objects.
     void Transfer(const GeckoSession::Window::LocalRef& inst,
                   jni::Object::Param aQueue,
                   jni::Object::Param aCompositor,
                   jni::Object::Param aDispatcher,
-                  jni::Object::Param aSettings);
+                  jni::Object::Param aInitData);
 
     void AttachEditable(const GeckoSession::Window::LocalRef& inst,
                         jni::Object::Param aEditableParent,
                         jni::Object::Param aEditableChild);
 
     void OnReady(jni::Object::Param aQueue = nullptr);
 };
 
@@ -758,26 +758,24 @@ nsWindow::NativePtr<nsWindow::NPZCSuppor
 bool nsWindow::NPZCSupport::sNegateWheelScroll;
 
 NS_IMPL_ISUPPORTS(nsWindow::AndroidView,
                   nsIAndroidEventDispatcher,
                   nsIAndroidView)
 
 
 nsresult
-nsWindow::AndroidView::GetSettings(JSContext* aCx, JS::MutableHandleValue aOut)
+nsWindow::AndroidView::GetInitData(JSContext* aCx, JS::MutableHandleValue aOut)
 {
-    if (!mSettings) {
+    if (!mInitData) {
         aOut.setNull();
         return NS_OK;
     }
 
-    // Lock to prevent races with UI thread.
-    auto lock = mSettings.Lock();
-    return widget::EventDispatcher::UnboxBundle(aCx, mSettings, aOut);
+    return widget::EventDispatcher::UnboxBundle(aCx, mInitData, aOut);
 }
 
 /**
  * Compositor has some unique requirements for its native calls, so make it
  * separate from GeckoViewSupport.
  */
 class nsWindow::LayerViewSupport final
     : public LayerSession::Compositor::Natives<LayerViewSupport>
@@ -1166,17 +1164,17 @@ nsWindow::GeckoViewSupport::~GeckoViewSu
 }
 
 /* static */ void
 nsWindow::GeckoViewSupport::Open(const jni::Class::LocalRef& aCls,
                                  GeckoSession::Window::Param aWindow,
                                  jni::Object::Param aQueue,
                                  jni::Object::Param aCompositor,
                                  jni::Object::Param aDispatcher,
-                                 jni::Object::Param aSettings,
+                                 jni::Object::Param aInitData,
                                  jni::String::Param aId,
                                  jni::String::Param aChromeURI,
                                  int32_t aScreenId,
                                  bool aPrivateMode)
 {
     MOZ_ASSERT(NS_IsMainThread());
 
     AUTO_PROFILER_LABEL("nsWindow::GeckoViewSupport::Open", OTHER);
@@ -1193,17 +1191,17 @@ nsWindow::GeckoViewSupport::Open(const j
             url = NS_LITERAL_CSTRING("chrome://geckoview/content/geckoview.xul");
         }
     }
 
     // Prepare an nsIAndroidView to pass as argument to the window.
     RefPtr<AndroidView> androidView = new AndroidView();
     androidView->mEventDispatcher->Attach(
             java::EventDispatcher::Ref::From(aDispatcher), nullptr);
-    androidView->mSettings = java::GeckoBundle::Ref::From(aSettings);
+    androidView->mInitData = java::GeckoBundle::Ref::From(aInitData);
 
     nsAutoCString chromeFlags("chrome,dialog=0,resizable,scrollbars");
     if (aPrivateMode) {
         chromeFlags += ",private";
     }
     nsCOMPtr<mozIDOMWindowProxy> domWindow;
     ww->OpenWindow(nullptr, url.get(), aId->ToCString().get(), chromeFlags.get(),
                    androidView, getter_AddRefs(domWindow));
@@ -1221,17 +1219,17 @@ nsWindow::GeckoViewSupport::Open(const j
     GeckoSession::Window::LocalRef sessionWindow(aCls.Env(), aWindow);
     window->mGeckoViewSupport =
             mozilla::MakeUnique<GeckoViewSupport>(window, sessionWindow);
     window->mGeckoViewSupport->mDOMWindow = pdomWindow;
     window->mAndroidView = androidView;
 
     // Attach other session support objects.
     window->mGeckoViewSupport->Transfer(
-            sessionWindow, aQueue, aCompositor, aDispatcher, aSettings);
+            sessionWindow, aQueue, aCompositor, aDispatcher, aInitData);
 
     if (window->mWidgetListener) {
         nsCOMPtr<nsIXULWindow> xulWindow(
                 window->mWidgetListener->GetXULWindow());
         if (xulWindow) {
             // Our window is not intrinsically sized, so tell nsXULWindow to
             // not set a size for us.
             xulWindow->SetIntrinsicallySized(false);
@@ -1255,17 +1253,17 @@ nsWindow::GeckoViewSupport::Close()
     mGeckoViewWindow = nullptr;
 }
 
 void
 nsWindow::GeckoViewSupport::Transfer(const GeckoSession::Window::LocalRef& inst,
                                      jni::Object::Param aQueue,
                                      jni::Object::Param aCompositor,
                                      jni::Object::Param aDispatcher,
-                                     jni::Object::Param aSettings)
+                                     jni::Object::Param aInitData)
 {
     if (window.mNPZCSupport) {
         MOZ_ASSERT(window.mLayerViewSupport);
         window.mNPZCSupport.Detach();
     }
 
     if (window.mLayerViewSupport) {
         window.mLayerViewSupport.Detach();
@@ -1273,20 +1271,24 @@ nsWindow::GeckoViewSupport::Transfer(con
 
     auto compositor = LayerSession::Compositor::LocalRef(
             inst.Env(), LayerSession::Compositor::Ref::From(aCompositor));
     window.mLayerViewSupport.Attach(compositor, &window, compositor);
 
     MOZ_ASSERT(window.mAndroidView);
     window.mAndroidView->mEventDispatcher->Attach(
             java::EventDispatcher::Ref::From(aDispatcher), mDOMWindow);
-    window.mAndroidView->mSettings = java::GeckoBundle::Ref::From(aSettings);
 
     if (mIsReady) {
+        // We're in a transfer; update init-data and notify JS code.
+        window.mAndroidView->mInitData =
+                java::GeckoBundle::Ref::From(aInitData);
         OnReady(aQueue);
+        window.mAndroidView->mEventDispatcher->Dispatch(
+                u"GeckoView:UpdateInitData");
     }
 
     DispatchToUiThread(
             "GeckoViewSupport::Transfer",
             [compositor = LayerSession::Compositor::GlobalRef(compositor)] {
                 compositor->OnCompositorAttached();
             });
 
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -161,17 +161,17 @@ private:
 
         AndroidView() {}
 
         NS_DECL_ISUPPORTS
         NS_DECL_NSIANDROIDVIEW
 
         NS_FORWARD_NSIANDROIDEVENTDISPATCHER(mEventDispatcher->)
 
-        mozilla::java::GeckoBundle::GlobalRef mSettings;
+        mozilla::java::GeckoBundle::GlobalRef mInitData;
     };
 
     RefPtr<AndroidView> mAndroidView;
 
     class LayerViewSupport;
     // Object that implements native LayerView calls.
     // Owned by the Java LayerView instance.
     NativePtr<LayerViewSupport> mLayerViewSupport;