--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -29,16 +29,17 @@ Cu.import("resource://gre/modules/Extens
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
var {
BaseContext,
SchemaAPIManager,
} = ExtensionCommon;
var {
+ MessageManagerProxy,
SpreadArgs,
defineLazyGetter,
findPathInObject,
} = ExtensionUtils;
const BASE_SCHEMA = "chrome://extensions/content/schemas/manifest.json";
const CATEGORY_EXTENSION_SCHEMAS = "webextension-schemas";
const CATEGORY_EXTENSION_SCRIPTS = "webextension-scripts";
@@ -229,62 +230,33 @@ GlobalManager = {
},
injectInObject(context, isChromeCompat, dest) {
apiManager.generateAPIs(context, dest);
SchemaAPIManager.generateAPIs(context, context.extension.apis, dest);
},
};
-class BrowserDocshellFollower {
- /**
- * Follows the <browser> belonging to the `xulBrowser`'s current docshell.
- *
- * @param {XULElement} xulBrowser A <browser> tag.
- * @param {function} onBrowserChange Called when the <browser> changes.
- */
- constructor(xulBrowser, onBrowserChange) {
- this.xulBrowser = xulBrowser;
- this.onBrowserChange = onBrowserChange;
-
- xulBrowser.addEventListener("SwapDocShells", this);
- }
-
- destroy() {
- this.xulBrowser.removeEventListener("SwapDocShells", this);
- this.xulBrowser = null;
- }
-
- handleEvent({detail: otherBrowser}) {
- this.xulBrowser.removeEventListener("SwapDocShells", this);
- this.xulBrowser = otherBrowser;
- this.xulBrowser.addEventListener("SwapDocShells", this);
- this.onBrowserChange(otherBrowser);
- }
-}
-
/**
* The proxied parent side of a context in ExtensionChild.jsm, for the
* parent side of a proxied API.
*/
class ProxyContextParent extends BaseContext {
constructor(envType, extension, params, xulBrowser, principal) {
super(envType, extension);
this.uri = NetUtil.newURI(params.url);
this.incognito = params.incognito;
// This message manager is used by ParentAPIManager to send messages and to
// close the ProxyContext if the underlying message manager closes. This
// message manager object may change when `xulBrowser` swaps docshells, e.g.
// when a tab is moved to a different window.
- this.currentMessageManager = xulBrowser.messageManager;
- this._docShellTracker = new BrowserDocshellFollower(
- xulBrowser, this.onBrowserChange.bind(this));
+ this.messageManagerProxy = new MessageManagerProxy(xulBrowser);
Object.defineProperty(this, "principal", {
value: principal, enumerable: true, configurable: true,
});
// TODO: Replace this with a Sandbox with our content principal when
// we move to separate processes.
if (params.cloneScope) {
@@ -297,36 +269,29 @@ class ProxyContextParent extends BaseCon
apiManager.emit("proxy-context-load", this);
}
get cloneScope() {
return this.sandbox;
}
- onBrowserChange(browser) {
- // Make sure that the message manager is set. Otherwise the ProxyContext may
- // never be destroyed because the ParentAPIManager would fail to detect that
- // the message manager is closed.
- if (!browser.messageManager) {
- throw new Error("BrowserDocshellFollower: The new browser has no message manager");
- }
-
- this.currentMessageManager = browser.messageManager;
+ get parentMessageManager() {
+ return this.messageManagerProxy.messageManager;
}
shutdown() {
this.unload();
}
unload() {
if (this.unloaded) {
return;
}
- this._docShellTracker.destroy();
+ this.messageManagerProxy.dispose();
super.unload();
apiManager.emit("proxy-context-unload", this);
}
}
defineLazyGetter(ProxyContextParent.prototype, "apiObj", function() {
let obj = {};
GlobalManager.injectInObject(this, false, obj);
@@ -404,17 +369,17 @@ ParentAPIManager = {
Services.mm.addMessageListener("API:AddListener", this);
Services.mm.addMessageListener("API:RemoveListener", this);
},
observe(subject, topic, data) {
if (topic === "message-manager-close") {
let mm = subject;
for (let [childId, context] of this.proxyContexts) {
- if (context.currentMessageManager === mm) {
+ if (context.parentMessageManager === mm) {
this.closeProxyContext(childId);
}
}
}
},
shutdownExtension(extensionId) {
for (let [childId, context] of this.proxyContexts) {
@@ -482,66 +447,66 @@ ParentAPIManager = {
if (context) {
context.unload();
this.proxyContexts.delete(childId);
}
},
call(data, target) {
let context = this.getContextById(data.childId);
- if (context.currentMessageManager !== target.messageManager) {
+ if (context.parentMessageManager !== target.messageManager) {
Cu.reportError("WebExtension warning: Message manager unexpectedly changed");
}
try {
let args = Cu.cloneInto(data.args, context.sandbox);
let result = findPathInObject(context.apiObj, data.path)(...args);
if (data.callId) {
result = result || Promise.resolve();
result.then(result => {
result = result instanceof SpreadArgs ? [...result] : [result];
- context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+ context.parentMessageManager.sendAsyncMessage("API:CallResult", {
childId: data.childId,
callId: data.callId,
result,
});
}, error => {
error = context.normalizeError(error);
- context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+ context.parentMessageManager.sendAsyncMessage("API:CallResult", {
childId: data.childId,
callId: data.callId,
error: {message: error.message},
});
});
}
} catch (e) {
if (data.callId) {
let error = context.normalizeError(e);
- context.currentMessageManager.sendAsyncMessage("API:CallResult", {
+ context.parentMessageManager.sendAsyncMessage("API:CallResult", {
childId: data.childId,
callId: data.callId,
error: {message: error.message},
});
} else {
Cu.reportError(e);
}
}
},
addListener(data, target) {
let context = this.getContextById(data.childId);
- if (context.currentMessageManager !== target.messageManager) {
+ if (context.parentMessageManager !== target.messageManager) {
Cu.reportError("WebExtension warning: Message manager unexpectedly changed");
}
function listener(...listenerArgs) {
- context.currentMessageManager.sendAsyncMessage("API:RunListener", {
+ context.parentMessageManager.sendAsyncMessage("API:RunListener", {
childId: data.childId,
path: data.path,
args: listenerArgs,
});
}
context.listenerProxies.set(data.path, listener);