Content frame message manager changes during life of tab

I have an app in a tab in my addon.

On load I do this:

var gCFMM = window.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIDocShell)
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIContentFrameMessageManager);

and then

gCFMM.addMessageListener(core.addon.id, bootstrapMsgListener);

throughout the page I use gCFMM.sendAsyncMessage

But eventually the page the sendAsyncMessage starts throwing an error:

NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIMessageSender.sendAsyncMessage]

I can fix this sendAsyncMessage by getting the gCFMM from window.QI. However because I did addMessageListener to the gCFMM on load, that listener is now not responding.

I have no idea how this can happen. I am on Firefox 45 beta, and was selected for the e10s a/b test.

How it happens is the frame message manager changes during the life of the tab :slight_smile: Don’t store it, just get it whenever you need it. The correct content frame message manager is always a global object in the frame script environment. You really shouldn’t be getting it from anywhere else.

One reason that this would happen is if the browser remoteness changed. docShell swaps are entirely expected and handled internally, but might leave you with dangling references. It could also happen if the remote process crashed, not quite so expected but still something that Firefox can recover from fairly cleanly. Probably there are other reasons too, best not to second-guess the internals.

Ah thanks for that info.

However what about my addMessageListener? I have to add that on load, and only a single time. Otherwise I would have to detect somehow that it changed and re addMessageListener no?

Should all be taken care of for you. Why go through all that pain extracting a message manager from a window when it is already provided for you?

So just what is going on here? Why do you even have something called window? Frame scripts don’t have window, they have content.

1 Like

Actually I haven’t really loaded a framescript. It’s a chrome://...xhtml page. So it’ a privelaged page, and I get the message manager for that “tab” I guess you can say by doing the above. It worked fine on everything till the latest nightly. I just noticed now in the Firefox 45 beta this is happening.

So you’re using frame script messaging from something that isn’t a frame script? I see a whole heap of pain. Can’t you just load a proper frame script into the xhtml page? Then it will be running in the right environment and everything should get taken care of automatically.

It won’t be pretty since right now there isn’t a good way to unload a frame script, but I’m sure you can work round that.

I think the frame script gets a frame script message manager and the content pages have a content message manager, I’m pretty sure there should be no issues :frowning:

My lack of knowledge of how your app works leads me to a question that may have an obvious answer, but: can’t you just re-add the listener in a try/catch?

FWIW I’ve never seen any mention of content message managers for content pages. I think the key here is in the terminology. There is a distinction between process message managers, which bridge the parent (chrome) process with its children (content) process(es) directly, and frame message managers, which can be specific to each window and browser elements (in the main process) and to each individual tab (in the content process).

I’ve never seen the nsIContentFrameMessageManager interface accessed like that, but just from looking at it, I believe you are just accessing a frame message manager that’s not specific to your content page per-se but to the frame script environment where your page… erm… resides? Is that the term?

Anyway, as Lithopsian mentioned, those can be reinitialized/recycled/whatever during the lifetime of a page, apparently without reloading it at all (this is news to me too), so if you’re just storing it as a var, then you can end up using an old reference. I’m not sure if it’s even possible to detect this happening within a content page / frame script though…

Maybe you should consider adding the listener in a frame script (the actual frame script and not from the content page) that’s assured to initialize when this happens, and have it interact with your app page.

Cross-process is tricky indeed, it took me months of trial and error to make sense of most of it, even after multiple reads of the docs:
https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Message_manager_overview

1 Like

Thanks so much, yes I can do try-catch but that is only on sendAsyncMessage (of course I can re addMessageListener in that same try-catch) but I’m trying to avoid this for two reasons:

  • Broadcasting a message there is no way to know if a content frame message manager got disconnected (it will just be skipped)
  • This has to work, it did forever, it still does, it’s just all finnicky now.

You are correct its not “content message manager” but in that MDN article you linked I am referring to “Content Frame Message Manager” section here - https://developer.mozilla.org/en-US/Firefox/Multiprocess_Firefox/Message_Manager/Message_manager_overview#Content_frame_message_manager

I really appreciate your detailed reply :slight_smile: