Bug 1364075 - remove DevTools dependency in ContentProcessSingleton;r=ochameau draft
authorJulian Descottes <jdescottes@mozilla.com>
Mon, 29 May 2017 23:36:26 +0200
changeset 586656 65b3aced59a7f5ceca35b2941c1ab1c80ac89b2b
parent 585803 4541134e973a6bd5e667a603e844854c8e5361da
child 631054 650e78fbf5d366cf206919b9e8ffe715c7d0be28
push id61476
push userjdescottes@mozilla.com
push dateTue, 30 May 2017 20:55:03 +0000
reviewersochameau
bugs1364075
milestone55.0a1
Bug 1364075 - remove DevTools dependency in ContentProcessSingleton;r=ochameau MozReview-Commit-ID: 38XKKM37jC5
devtools/client/framework/devtools-browser.js
devtools/server/content-process-debugger-server.js
devtools/server/main.js
devtools/server/moz.build
toolkit/components/processsingleton/ContentProcessSingleton.js
--- a/devtools/client/framework/devtools-browser.js
+++ b/devtools/client/framework/devtools-browser.js
@@ -852,16 +852,19 @@ var gDevToolsBrowser = exports.gDevTools
 
     gDevToolsBrowser._pingTelemetry();
     gDevToolsBrowser._telemetry = null;
 
     for (let win of gDevToolsBrowser._trackedBrowserWindows) {
       gDevToolsBrowser._forgetBrowserWindow(win);
     }
 
+    // Remove scripts loaded in content process to support the Browser Content Toolbox.
+    DebuggerServer.removeContentServerScript();
+
     gDevTools.destroy({ shuttingDown });
   },
 };
 
 // Handle all already registered tools,
 gDevTools.getToolDefinitionArray()
          .forEach(def => gDevToolsBrowser._addToolToWindows(def));
 // and the new ones.
new file mode 100644
--- /dev/null
+++ b/devtools/server/content-process-debugger-server.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* global addMessageListener, removeMessageListener */
+
+"use strict";
+
+const { utils: Cu } = Components;
+const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
+
+function onInit(message) {
+  // Only reply if we are in a real content process
+  if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
+    let {init} = Cu.import("resource://devtools/server/content-server.jsm", {});
+    init(message);
+  }
+}
+
+function onClose() {
+  removeMessageListener("debug:init-content-server", onInit);
+  removeMessageListener("debug:close-content-server", onClose);
+}
+
+addMessageListener("debug:init-content-server", onInit);
+addMessageListener("debug:close-content-server", onClose);
--- a/devtools/server/main.js
+++ b/devtools/server/main.js
@@ -64,16 +64,19 @@ if (isWorker) {
   const VERBOSE_PREF = "devtools.debugger.log.verbose";
 
   flags.wantLogging = Services.prefs.getBoolPref(LOG_PREF);
   flags.wantVerbose =
     Services.prefs.getPrefType(VERBOSE_PREF) !== Services.prefs.PREF_INVALID &&
     Services.prefs.getBoolPref(VERBOSE_PREF);
 }
 
+const CONTENT_PROCESS_DBG_SERVER_SCRIPT =
+  "resource://devtools/server/content-process-debugger-server.js";
+
 function loadSubScript(url) {
   try {
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
                    .getService(Ci.mozIJSSubScriptLoader);
     loader.loadSubScript(url, this);
   } catch (e) {
     let errorStr = "Error loading: " + url + ":\n" +
                    (e.fileName ? "at " + e.fileName + " : " + e.lineNumber + "\n" : "") +
@@ -144,16 +147,18 @@ function ModuleAPI() {
 }
 
 /** *
  * Public API
  */
 var DebuggerServer = {
   _listeners: [],
   _initialized: false,
+  // Flag to check if the content process debugger server script was already loaded.
+  _contentProcessScriptLoaded: false,
   // Map of global actor names to actor constructors provided by extensions.
   globalActorFactories: {},
   // Map of tab actor names to actor constructors provided by extensions.
   tabActorFactories: {},
 
   LONG_STRING_LENGTH: 10000,
   LONG_STRING_INITIAL_LENGTH: 1000,
   LONG_STRING_READ_LENGTH: 65 * 1024,
@@ -750,17 +755,26 @@ var DebuggerServer = {
 
       dumpn("establishing forwarding for process with prefix " + prefix);
 
       actor = msg.json.actor;
 
       deferred.resolve(actor);
     });
 
-    mm.sendAsyncMessage("DevTools:InitDebuggerServer", {
+    // Load the content process debugger server script only once.
+    if (!this._contentProcessScriptLoaded) {
+      // Load the process script that will receive the debug:init-content-server message
+      Services.ppmm.loadProcessScript(CONTENT_PROCESS_DBG_SERVER_SCRIPT, true);
+      this._contentProcessScriptLoaded = true;
+    }
+
+    // Send a message to the content process debugger server script to forward it the
+    // prefix.
+    mm.sendAsyncMessage("debug:init-content-server", {
       prefix: prefix
     });
 
     function onClose() {
       Services.obs.removeObserver(onMessageManagerClose, "message-manager-close");
       events.off(connection, "closed", onClose);
       if (childTransport) {
         // If we have a child transport, the actor has already
@@ -1364,16 +1378,30 @@ var DebuggerServer = {
         for (let connID of Object.getOwnPropertyNames(this._connections)) {
           this._connections[connID].rootActor.removeActorByName(name);
         }
       }
     }
   },
 
   /**
+   * Called when DevTools are unloaded to remove the contend process server script for the
+   * list of scripts loaded for each new content process. Will also remove message
+   * listeners from already loaded scripts.
+   */
+  removeContentServerScript() {
+    Services.ppmm.removeDelayedProcessScript(CONTENT_PROCESS_DBG_SERVER_SCRIPT);
+    try {
+      Services.ppmm.broadcastAsyncMessage("debug:close-content-server");
+    } catch (e) {
+      // Nothing to do
+    }
+  },
+
+  /**
    * ⚠ TESTING ONLY! ⚠ Searches all active connections for an actor matching an ID.
    * This is helpful for some tests which depend on reaching into the server to check some
    * properties of an actor.
    */
   _searchAllConnectionsForActor(actorID) {
     for (let connID of Object.getOwnPropertyNames(this._connections)) {
       let actor = this._connections[connID].getActor(actorID);
       if (actor) {
--- a/devtools/server/moz.build
+++ b/devtools/server/moz.build
@@ -13,16 +13,17 @@ DIRS += [
 ]
 
 BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
 MOCHITEST_CHROME_MANIFESTS += ['tests/mochitest/chrome.ini']
 XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
 
 DevToolsModules(
     'child.js',
+    'content-process-debugger-server.js',
     'content-server.jsm',
     'css-logic.js',
     'event-parsers.js',
     'main.js',
     'primitive.js',
     'service-worker-child.js',
     'websocket-server.js',
     'worker.js'
--- a/toolkit/components/processsingleton/ContentProcessSingleton.js
+++ b/toolkit/components/processsingleton/ContentProcessSingleton.js
@@ -44,17 +44,16 @@ ContentProcessSingleton.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   observe(subject, topic, data) {
     switch (topic) {
     case "app-startup": {
       Services.obs.addObserver(this, "console-api-log-event");
       Services.obs.addObserver(this, "xpcom-shutdown");
-      cpmm.addMessageListener("DevTools:InitDebuggerServer", this);
       TelemetryController.observe(null, topic, null);
       break;
     }
     case "console-api-log-event": {
       let consoleMsg = subject.wrappedJSObject;
 
       let msgData = {
         level: consoleMsg.level,
@@ -98,24 +97,14 @@ ContentProcessSingleton.prototype = {
 
       cpmm.sendAsyncMessage("Console:Log", msgData);
       break;
     }
 
     case "xpcom-shutdown":
       Services.obs.removeObserver(this, "console-api-log-event");
       Services.obs.removeObserver(this, "xpcom-shutdown");
-      cpmm.removeMessageListener("DevTools:InitDebuggerServer", this);
       break;
     }
   },
-
-  receiveMessage(message) {
-    // load devtools component on-demand
-    // Only reply if we are in a real content process
-    if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
-      let {init} = Cu.import("resource://devtools/server/content-server.jsm", {});
-      init(message);
-    }
-  },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentProcessSingleton]);