Bug 1320395: Part 2 - Assign extension's process message manager based on first view load. r=billm
authorKris Maglione <maglione.k@gmail.com>
Sun, 27 Nov 2016 12:49:16 -0800
changeset 375039 a1eb055f4caf5cb16c9630ce7fcb4704be4cb74b
parent 375038 c59832caf8dbfb88f48e7a336702891cbae0b913
child 375040 353d75e97b1e3e98795512fe9e783b01324eb6c1
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1320395
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1320395: Part 2 - Assign extension's process message manager based on first view load. r=billm MozReview-Commit-ID: GLKjyR46O0Z
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionParent.jsm
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -625,16 +625,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;
@@ -644,27 +646,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;
   }
 
@@ -951,17 +942,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);
   },