Bug 1320395: Part 2 - Assign extension's process message manager based on first view load. r?billm
MozReview-Commit-ID: GLKjyR46O0Z
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -608,16 +608,18 @@ this.Extension = class extends Extension
this.addonData = addonData;
this.startupReason = startupReason;
this.remote = ExtensionManagement.useRemoteWebExtensions;
if (this.remote && processCount !== 1) {
throw new Error("Out-of-process WebExtensions are not supported with multiple child processes");
}
+ // This is filled in the first time an extension child is created.
+ this.parentMessageManager = null;
this.id = addonData.id;
this.baseURI = NetUtil.newURI(this.getURL("")).QueryInterface(Ci.nsIURL);
this.principal = this.createPrincipal();
this.onStartup = null;
this.hasShutdown = false;
@@ -627,27 +629,16 @@ this.Extension = class extends Extension
this.apis = [];
this.whiteListedHosts = null;
this.webAccessibleResources = null;
this.emitter = new EventEmitter();
}
- get parentMessageManager() {
- if (this.remote) {
- // We currently run extensions in the normal web content process. Since
- // we currently only support remote extensions in single-child e10s,
- // child 0 is always the current process, and child 1 is always the
- // remote extension process.
- return Services.ppmm.getChildAt(1);
- }
- return Services.ppmm.getChildAt(0);
- }
-
static set browserUpdated(updated) {
_browserUpdated = updated;
}
static get browserUpdated() {
return _browserUpdated;
}
@@ -934,17 +925,17 @@ this.Extension = class extends Extension
MessageChannel.abortResponses({extensionId: this.id});
ExtensionManagement.shutdownExtension(this.uuid);
this.cleanupGeneratedFile();
}
observe(subject, topic, data) {
- if (topic == "xpcom-shutdown") {
+ if (topic === "xpcom-shutdown") {
this.cleanupGeneratedFile();
}
}
hasPermission(perm) {
let match = /^manifest:(.*)/.exec(perm);
if (match) {
return this.manifest[match[1]] != null;
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -387,65 +387,87 @@ ParentAPIManager = {
observe(subject, topic, data) {
if (topic === "message-manager-close") {
let mm = subject;
for (let [childId, context] of this.proxyContexts) {
if (context.parentMessageManager === mm) {
this.closeProxyContext(childId);
}
}
+
+ // Reset extension message managers when their child processes shut down.
+ for (let extension of GlobalManager.extensionMap.values()) {
+ if (extension.parentMessageManager === mm) {
+ extension.parentMessageManager = null;
+ }
+ }
}
},
shutdownExtension(extensionId) {
for (let [childId, context] of this.proxyContexts) {
if (context.extension.id == extensionId) {
context.shutdown();
this.proxyContexts.delete(childId);
}
}
},
receiveMessage({name, data, target}) {
- switch (name) {
- case "API:CreateProxyContext":
- this.createProxyContext(data, target);
- break;
+ try {
+ switch (name) {
+ case "API:CreateProxyContext":
+ this.createProxyContext(data, target);
+ break;
- case "API:CloseProxyContext":
- this.closeProxyContext(data.childId);
- break;
+ case "API:CloseProxyContext":
+ this.closeProxyContext(data.childId);
+ break;
- case "API:Call":
- this.call(data, target);
- break;
+ case "API:Call":
+ this.call(data, target);
+ break;
- case "API:AddListener":
- this.addListener(data, target);
- break;
+ case "API:AddListener":
+ this.addListener(data, target);
+ break;
- case "API:RemoveListener":
- this.removeListener(data);
- break;
+ case "API:RemoveListener":
+ this.removeListener(data);
+ break;
+ }
+ } catch (e) {
+ Cu.reportError(e);
}
},
createProxyContext(data, target) {
let {envType, extensionId, childId, principal} = data;
if (this.proxyContexts.has(childId)) {
throw new Error("A WebExtension context with the given ID already exists!");
}
let extension = GlobalManager.getExtension(extensionId);
if (!extension) {
throw new Error(`No WebExtension found with ID ${extensionId}`);
}
let context;
if (envType == "addon_parent" || envType == "devtools_parent") {
+ let processMessageManager = (target.messageManager.processMessageManager ||
+ Services.ppmm.getChildAt(0));
+
+ if (!extension.parentMessageManager) {
+ extension.parentMessageManager = processMessageManager;
+ }
+
+ if (processMessageManager !== extension.parentMessageManager) {
+ throw new Error("Attempt to create privileged extension parent from incorrect child process");
+ }
+
context = new ExtensionPageContextParent(envType, extension, data, target);
} else if (envType == "content_parent") {
context = new ContentScriptContextParent(envType, extension, data, target, principal);
} else {
throw new Error(`Invalid WebExtension context envType: ${envType}`);
}
this.proxyContexts.set(childId, context);
},