Bug 1320395: Part 3 - Run WebExtensions in their own process type. r?billm,bobowen f?pauljt draft
authorKris Maglione <maglione.k@gmail.com>
Fri, 25 Nov 2016 16:36:14 -0800
changeset 444204 756aeabe5622f1af6118f4a057faaed046e71091
parent 444203 049c802e5b09dbbfc9a7a2be6d049b0d5b368e03
child 538264 4c51e9255ffc34c72948c1a94e99433ec2620083
push id37231
push usermaglione.k@gmail.com
push dateSun, 27 Nov 2016 20:59:46 +0000
reviewersbillm, bobowen
bugs1320395
milestone53.0a1
Bug 1320395: Part 3 - Run WebExtensions in their own process type. r?billm,bobowen f?pauljt 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
@@ -227,16 +227,17 @@ class BasePopup {
 
   createBrowser(viewNode, popupURL = null) {
     let document = viewNode.ownerDocument;
     let browser = document.createElementNS(XUL_NS, "browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("transparent", "true");
     browser.setAttribute("class", "webextension-popup-browser");
+    browser.setAttribute("remoteType", "extension");
     browser.setAttribute("webextension-view-type", "popup");
     browser.setAttribute("tooltip", "aHTMLTooltip");
 
     if (this.extension.remote) {
       browser.setAttribute("remote", "true");
     }
 
     // We only need flex sizing for the sake of the slide-in sub-views of the
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -20,19 +20,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
@@ -28,28 +28,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: function(aURL, aProcess) {
     let remoteType = aProcess == Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT
                      ? DEFAULT_REMOTE_TYPE : NOT_REMOTE;
     return remoteType == this.getRemoteTypeForURI(aURL, true, remoteType);
   },
 
   getRemoteTypeForURI: function(aURL, aMultiProcess,
@@ -127,17 +129,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
@@ -32,16 +32,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
@@ -300,18 +300,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 === "extension";
+    }
+    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
@@ -451,17 +451,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 ? "extension" : 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
@@ -47,16 +47,17 @@ class BackgroundPageBase {
         url = this.extension.baseURI.resolve("_blank.html");
       }
 
       let chromeDoc = yield this.getParentDocument();
 
       let browser = chromeDoc.createElement("browser");
       browser.setAttribute("type", "content");
       browser.setAttribute("disableglobalhistory", "true");
+      browser.setAttribute("remoteType", "extension");
       browser.setAttribute("webextension-view-type", "background");
 
       let awaitFrameLoader;
       if (this.extension.remote) {
         browser.setAttribute("remote", "true");
         awaitFrameLoader = promiseEvent(browser, "XULFrameLoaderCreated");
       }
 
--- 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
@@ -3529,16 +3529,17 @@ var gDetailView = {
     }
   },
 
   createOptionsBrowser: Task.async(function*(parentNode) {
     let browser = document.createElement("browser");
     browser.setAttribute("type", "content");
     browser.setAttribute("disableglobalhistory", "true");
     browser.setAttribute("class", "inline-options-browser");
+    browser.setAttribute("remoteType", "extension");
 
     let {optionsURL} = this._addon;
     let remote = !E10SUtils.canLoadURIInProcess(optionsURL, Services.appinfo.PROCESS_TYPE_DEFAULT);
 
     let readyPromise;
     if (remote) {
       browser.setAttribute("remote", "true");
       readyPromise = promiseEvent("XULFrameLoaderCreated", browser);