Bug 1320395: Part 3 - Run WebExtensions in their own process type. r=billm,bobowen
authorKris Maglione <maglione.k@gmail.com>
Thu, 12 Jan 2017 14:11:47 -0800
changeset 375040 353d75e97b1e3e98795512fe9e783b01324eb6c1
parent 375039 a1eb055f4caf5cb16c9630ce7fcb4704be4cb74b
child 375041 1f5a359e77c4282522141e99ad1e95f9a579154c
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, bobowen
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 3 - Run WebExtensions in their own process type. r=billm,bobowen MozReview-Commit-ID: FZ4f1Lda5vh
browser/components/extensions/ext-utils.js
browser/components/extensions/test/browser/head.js
browser/modules/E10SUtils.jsm
dom/ipc/ContentParent.h
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionManagement.jsm
toolkit/components/extensions/ExtensionParent.jsm
toolkit/components/extensions/ext-backgroundPage.js
toolkit/components/extensions/test/mochitest/head.js
toolkit/mozapps/extensions/content/extensions.js
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -1,14 +1,16 @@
 /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set sts=2 sw=2 et tw=80: */
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
                                   "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
                                   "resource://gre/modules/Timer.jsm");
@@ -228,16 +230,17 @@ class BasePopup {
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("transparent", "true");
     browser.setAttribute("class", "webextension-popup-browser");
     browser.setAttribute("webextension-view-type", "popup");
     browser.setAttribute("tooltip", "aHTMLTooltip");
 
     if (this.extension.remote) {
       browser.setAttribute("remote", "true");
+      browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
     }
 
     // We only need flex sizing for the sake of the slide-in sub-views of the
     // main menu panel, so that the browser occupies the full width of the view,
     // and also takes up any extra height that's available to it.
     browser.setAttribute("flex", "1");
 
     // Note: When using noautohide panels, the popup manager will add width and
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -21,19 +21,22 @@ const {AppConstants} = Cu.import("resour
 const {CustomizableUI} = Cu.import("resource:///modules/CustomizableUI.jsm", {});
 
 // We run tests under two different configurations, from browser.ini and
 // browser-remote.ini. When running from browser-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
 // use to select our configuration.
 if (gTestPath.includes("test-oop-extensions")) {
   SpecialPowers.pushPrefEnv({set: [
-    ["dom.ipc.processCount", 1],
+    ["dom.ipc.processCount.extension", 1],
     ["extensions.webextensions.remote", true],
   ]});
+  // We don't want to reset this at the end of the test, so that we don't have
+  // to spawn a new extension child process for each test unit.
+  SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
 }
 
 // Bug 1239884: Our tests occasionally hit a long GC pause at unpredictable
 // times in debug builds, which results in intermittent timeouts. Until we have
 // a better solution, we force a GC after certain strategic tests, which tend to
 // accumulate a high number of unreaped windows.
 function forceGC() {
   if (AppConstants.DEBUG) {
--- a/browser/modules/E10SUtils.jsm
+++ b/browser/modules/E10SUtils.jsm
@@ -29,28 +29,30 @@ function getAboutModule(aURL) {
   }
 }
 
 const NOT_REMOTE = null;
 
 // These must match any similar ones in ContentParent.h.
 const WEB_REMOTE_TYPE = "web";
 const FILE_REMOTE_TYPE = "file";
+const EXTENSION_REMOTE_TYPE = "extension";
 const DEFAULT_REMOTE_TYPE = WEB_REMOTE_TYPE;
 
 function validatedWebRemoteType(aPreferredRemoteType) {
   return aPreferredRemoteType && aPreferredRemoteType.startsWith(WEB_REMOTE_TYPE)
          ? aPreferredRemoteType : WEB_REMOTE_TYPE;
 }
 
 this.E10SUtils = {
   DEFAULT_REMOTE_TYPE,
   NOT_REMOTE,
   WEB_REMOTE_TYPE,
   FILE_REMOTE_TYPE,
+  EXTENSION_REMOTE_TYPE,
 
   canLoadURIInProcess(aURL, aProcess) {
     let remoteType = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT
                      ? DEFAULT_REMOTE_TYPE : NOT_REMOTE;
     return remoteType == this.getRemoteTypeForURI(aURL, true, remoteType);
   },
 
   getRemoteTypeForURI(aURL, aMultiProcess,
@@ -128,17 +130,17 @@ this.E10SUtils = {
           aPreferredRemoteType != NOT_REMOTE) {
         return DEFAULT_REMOTE_TYPE;
       }
 
       return NOT_REMOTE;
     }
 
     if (aURL.startsWith("moz-extension:")) {
-      return useRemoteWebExtensions ? WEB_REMOTE_TYPE : NOT_REMOTE;
+      return useRemoteWebExtensions ? EXTENSION_REMOTE_TYPE : NOT_REMOTE;
     }
 
     if (aURL.startsWith("view-source:")) {
       return this.getRemoteTypeForURI(aURL.substr("view-source:".length),
                                       aMultiProcess, aPreferredRemoteType);
     }
 
     return validatedWebRemoteType(aPreferredRemoteType);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -33,16 +33,17 @@
 
 #define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
 
 #define NO_REMOTE_TYPE ""
 
 // These must match the similar ones in E10SUtils.jsm.
 #define DEFAULT_REMOTE_TYPE "web"
 #define FILE_REMOTE_TYPE "file"
+#define EXTENSION_REMOTE_TYPE "extension"
 
 // This must start with the DEFAULT_REMOTE_TYPE above.
 #define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
 
 class nsConsoleService;
 class nsICycleCollectorLogSink;
 class nsIDumpGCAndCCLogsCallback;
 class nsITabParent;
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -23,17 +23,17 @@ const Cr = Components.results;
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 /* globals processCount */
 
-XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount");
+XPCOMUtils.defineLazyPreferenceGetter(this, "processCount", "dom.ipc.processCount.extension");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionAPIs",
                                   "resource://gre/modules/ExtensionAPI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
--- a/toolkit/components/extensions/ExtensionManagement.jsm
+++ b/toolkit/components/extensions/ExtensionManagement.jsm
@@ -10,16 +10,18 @@ const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cu = Components.utils;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
                                   "resource://gre/modules/ExtensionUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "console", () => ExtensionUtils.getConsole());
 
 XPCOMUtils.defineLazyGetter(this, "UUIDMap", () => {
   let {UUIDMap} = Cu.import("resource://gre/modules/Extension.jsm", {});
   return UUIDMap;
@@ -300,18 +302,20 @@ function getAPILevelForWindow(window, ad
   }
 
   // WebExtension URLs loaded into top frames UI could have full API level privileges.
   return FULL_PRIVILEGES;
 }
 
 ExtensionManagement = {
   get isExtensionProcess() {
-    return (this.useRemoteWebExtensions ||
-            Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT);
+    if (this.useRemoteWebExtensions) {
+      return Services.appinfo.remoteType === E10SUtils.EXTENSION_REMOTE_TYPE;
+    }
+    return Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
   },
 
   startupExtension: Service.startupExtension.bind(Service),
   shutdownExtension: Service.shutdownExtension.bind(Service),
 
   registerAPI: APIs.register.bind(APIs),
   unregisterAPI: APIs.unregister.bind(APIs),
 
--- a/toolkit/components/extensions/ExtensionParent.jsm
+++ b/toolkit/components/extensions/ExtensionParent.jsm
@@ -17,16 +17,18 @@ this.EXPORTED_SYMBOLS = ["ExtensionParen
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppConstants",
                                   "resource://gre/modules/AppConstants.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MessageChannel",
                                   "resource://gre/modules/MessageChannel.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NativeApp",
                                   "resource://gre/modules/NativeMessaging.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Schemas",
                                   "resource://gre/modules/Schemas.jsm");
@@ -451,17 +453,20 @@ ParentAPIManager = {
     }
 
     let context;
     if (envType == "addon_parent" || envType == "devtools_parent") {
       let processMessageManager = (target.messageManager.processMessageManager ||
                                    Services.ppmm.getChildAt(0));
 
       if (!extension.parentMessageManager) {
-        extension.parentMessageManager = processMessageManager;
+        let expectedRemoteType = extension.remote ? E10SUtils.EXTENSION_REMOTE_TYPE : null;
+        if (target.remoteType === expectedRemoteType) {
+          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") {
--- a/toolkit/components/extensions/ext-backgroundPage.js
+++ b/toolkit/components/extensions/ext-backgroundPage.js
@@ -2,16 +2,18 @@
 
 var {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "E10SUtils",
+                                  "resource:///modules/E10SUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
                                   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 
 Cu.import("resource://gre/modules/ExtensionUtils.jsm");
 const {
   promiseDocumentLoaded,
   promiseEvent,
   promiseObserved,
@@ -52,16 +54,17 @@ class BackgroundPageBase {
       let browser = chromeDoc.createElement("browser");
       browser.setAttribute("type", "content");
       browser.setAttribute("disableglobalhistory", "true");
       browser.setAttribute("webextension-view-type", "background");
 
       let awaitFrameLoader;
       if (this.extension.remote) {
         browser.setAttribute("remote", "true");
+        browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
         awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
       }
 
       chromeDoc.documentElement.appendChild(browser);
       yield awaitFrameLoader;
 
       this.browser = browser;
 
--- a/toolkit/components/extensions/test/mochitest/head.js
+++ b/toolkit/components/extensions/test/mochitest/head.js
@@ -1,19 +1,22 @@
 "use strict";
 
 // We run tests under two different configurations, from mochitest.ini and
 // mochitest-remote.ini. When running from mochitest-remote.ini, the tests are
 // copied to the sub-directory "test-oop-extensions", which we detect here, and
 // use to select our configuration.
 if (location.pathname.includes("test-oop-extensions")) {
   SpecialPowers.pushPrefEnv({set: [
-    ["dom.ipc.processCount", 1],
+    ["dom.ipc.processCount.extension", 1],
     ["extensions.webextensions.remote", true],
   ]});
+  // We don't want to reset this at the end of the test, so that we don't have
+  // to spawn a new extension child process for each test unit.
+  SpecialPowers.setIntPref("dom.ipc.keepProcessesAlive.extension", 1);
 }
 
 /* exported waitForLoad */
 
 function waitForLoad(win) {
   return new Promise(resolve => {
     win.addEventListener("load", function listener() {
       win.removeEventListener("load", listener, true);
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -3527,16 +3527,17 @@ var gDetailView = {
     browser.setAttribute("class", "inline-options-browser");
 
     let {optionsURL} = this._addon;
     let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
 
     let readyPromise;
     if (remote) {
       browser.setAttribute("remote", "true");
+      browser.setAttribute("remoteType", E10SUtils.EXTENSION_REMOTE_TYPE);
       readyPromise = promiseEvent("XULFrameLoaderCreated", browser);
     } else {
       readyPromise = promiseEvent("load", browser, true);
     }
 
     parentNode.appendChild(browser);
 
     // Force bindings to apply synchronously.