Calling add-on from web page in new multiprocess Firefox

Hello everyone.

I faced problem with new multiprocess API migration (E10S aka Electrolysis).

Our web part interacts with extension which collaborates with native library written in C (we utilize c-types lib for this part).

Now Firefox is moving to multiprocess model that requires code adaptation. The most significant and complicated part for now is content-to-extension communication reimplementation. It was implemented according to related official documentation

We used bootstrap extension initialization in following manner:

function startup(params, reason) {
    include("chrome/content/extmain.js");

    mainWindow = winMediator.getMostRecentWindow("navigator:browser");
    if (null == mainWindow) {
        var windowListenerWidget = {
            onOpenWindow: function (aWindow) {
                winMediator.removeListener(windowListenerWidget);
                var mainWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);

                mainWindow.addEventListener("load", function onWindowLoad() {
                    mainWindow.removeEventListener("load", onWindowLoad);
                    addAddonListener(mainWindow);
                });

            },
            onCloseWindow: function (aWindow) {
            },
            onWindowTitleChange: function (aWindow, aTitle) {
            }
        };
        winMediator.addListener(windowListenerWidget);
    } else {
        addAddonListener(mainWindow);
    }
}

function addAddonListener(win) {
    win.document.addEventListener(
        "CryptoApiExtension_HandleMsg",
        function (event) {
            var node = event.target;
            if (!node || node.nodeType != 3) {
                return;
            }
            var response = CryptoApiExtension.handleMessage(JSON.parse(node.nodeValue));
            var doc = node.ownerDocument;
            node.nodeValue = JSON.stringify(response);
            var event = doc.createEvent("HTMLEvents");
            event.initEvent("CryptoApiExtension_response", true, false);
            return node.dispatchEvent(event);
        }, false, true);
}

This code above was broken with new multiprocess architecture. There are lot of documentation we have read, but still there’s no way we could handle this issue.

The question is: how to adapt this code to make extension accept web page invocations?

Events will not propagate between processes. Although some of them appear to do so, this is generally because something behind the scenes is catching them, sending them to the other process by message, then re-emitting the event. So you have to use one of the inter-process messaging methods.

You mention calling the addon from a web page. Is this really what you’re doing, or is it actually from a content script or page script created by the addon? The exact communication method depends on what kind of script you have in the content process. For example, interacting with web content from an addon can be done using frame scripts, which can communicate with the chrome process using built-in messing functions that can pass cloned data, or even object wrappers:
https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Communicating_with_frame_scripts

You no longer need that window listener.

All you have to do now is:

 Services.mm.loadFrameScript('data:,console.log("hi");var gCFMM = this;content.document.addEventListener("CryptoApiExtension_HandleMsg", function() { gCFMM.sendAsyncMessage("your:addon:id", "CryptoAPIGotMessage" })', true);

Then in your bootstrap.js set up an observer to respond to this:

var fsMsgListener = {
    receiveMessage: function(aMsgEvent) {
        if (aMsgEvent.data == '') {
            // 'do something'
            // to send message back to the content that send this message do:
            aMsgEvent.target.messageManager.sendAsyncMessage("your:addon:id", "data to send");
            // but make sure to set up an message listener in the framescript for this
        }
    }
}
Services.mm.addMessageListener("your:addon:id", fsMsgListener);

Mine here has a helper function which is a bit complicated, but if you can understand it, it makes things super easy, the helper is “sendAsyncMessageWithCallback”:smile:
https://github.com/Noitidart/Tweeeeeeeeeeeeeeeeeeter/blob/master/bootstrap.js