mozilla

Toggle fullscreen

Electrolysis (e10s) for Firefox Hackers

45 minutes is not enough, but please ask questions now or after

The big picture

Terminology

I will likely interchange the following without noticing, purely out of habit (sorry).

"IPC" stands for "inter-process communication".

A "remote browser" is a <xul:browser> with the remote="true" attribute.

A "frame script" is a script that can be sent to a child process to hear and respond to messages

Things browser hackers need to know

Message managers

There are several types, and different types are available depending on which process you're in.

Check out the documentation for message managers on MDN and the documentation in nsIMessageManager.idl for a low-level breakdown.

The one you're most likely to work with is the "browser" message manager.

        let browser = gBrowser.selectedBrowser;
        let mm = browser.messageManager;
        //  ^-- Available even if <xul:browser> is not remote!
        mm.sendAsyncMessage("Foo", {
          bar: "baz", // JSON serializable stuff and nsIPrincipal's can go in here.
        });

        mm.addMessageListener("Done", (message) => {
          dump("Child sent done.");
        });
        -- snip --

        // Inside some frame script:
        addMessageListener("Foo", (message) => {
          dump("Parent said: " + message.data.bar + "\n");
          sendAsyncMessage("Done"); // Could also use sendSyncMessage("Done");
        });

If the chrome needs to touch content...

If content needs to talk to chrome, send a message to the parent from a frame script.

Loading frame scripts

        let browser = gBrowser.selectedBrowser;
        let mm = browser.messageManager;
        mm.loadFrameScript("chrome://browser/content/foo.js", false);
        // Set second arg to true if we want to load this once remote browser
        // is ready / available. Otherwise, script will only load if remote
        // browser is ready / available.
      

Important pre-existing frame scripts

Loaded in all <xul:browser>'s, remote or not:

Loaded just in remote <xul:browser>'s:

Bi-directional CPOWs

Intentionally sending a CPOW

Sometimes, a CPOW is just the best way forward.

        // Some frame script
        addEventListener("click", (event) => {
          sendAsyncMessage("Foo:Click", null, {
            target: event.target,
          });
        });
      
        -- snip --

        // Parent process script
        let mm = gBrowser.selectedBrowser.messageManager;
        mm.addMessageListener("Foo:Click", (message) => {
          dump("I got the item with ID: " + message.objects.target.id);
        });
      

Some anti-patterns with CPOWs

Lots of CPOW traffic - use a frame script instead.

        let doc = gBrowser.selectedBrowser.contentDocumentAsCPOW;
        let anchors = doc.querySelectorAll("a");
        for (let anchor of anchors) {
          if (anchor.href.startsWith("https://")) {
            el.classList.add("ssl");
          }
        }
      

Just focus the browser element

        let win = gBrowser.selectedBrowser.contentWindowAsCPOW;
        win.focus();
      

This is likely going to explode in interesting ways.

        let win = gBrowser.selectedBrowser.contentWindowAsCPOW;
        let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);

        let svc = Cc["@mozilla.org/someservice;1"].getService(Ci.nsISomeService);
        svc.someMethod(docShell);
      

A few words on add-on shimming

Questions!

Thanks!

/