Files
palemoon27/toolkit/devtools/server/docs/lazy-actor-modules.md
T

3.9 KiB

Lazy Actor Modules and E10S setup

The DebuggerServer loads and creates most of the actors lazily to keep the initial memory usage down (which is extremely important on lower end devices).

Register a lazy global/tab actor module

register a global actor:

    DebuggerServer.registerModule("devtools/server/actors/webapps", {
      prefix: "webapps",
      constructor: "WebappsActor",
      type: { global: true }
    });

register a tab actor:

    DebuggerServer.registerModule("devtools/server/actors/webconsole", {
      prefix: "console",
      constructor: "WebConsoleActor",
      type: { tab: true }
    });

E10S Setup

Some of the actor modules needs to exchange messages between the parent and child processes.

E.g. the director-manager needs to ask the list installed director scripts from the director-registry running in the parent process) and the parent/child setup is lazily directed by the DebuggerServer.

When the actor is loaded for the first time in the the DebuggerServer running in the child process, it has the chances to run its setup procedure, e.g. in the director-registry:

...
const {DebuggerServer} = require("devtools/server/main");

...

// skip child setup if this actor module is not running in a child process
if (DebuggerServer.isInChildProcess) {
  setupChildProcess();
}
...

The above setupChildProcess helper will use the DebuggerServer.setupInParent to start a setup process in the parent process Debugger Server, e.g. in the the director-registry:

function setupChildProcess() {
  const { sendSyncMessage } = DebuggerServer.parentMessageManager;

  DebuggerServer.setupInParent({
    module: "devtools/server/actors/director-registry",
    setupParent: "setupParentProcess"
  });

  ...

in the parent process, the DebuggerServer will require the requested module and call the setupParent exported helper with the MessageManager connected to the child process as parameter, e.g. in the director-registry:

/**
 * E10S parent/child setup helpers
 */

let gTrackedMessageManager = new Set();

exports.setupParentProcess = function setupParentProcess({ mm, childID }) {
  if (gTrackedMessageManager.has(mm)) { return; }
  gTrackedMessageManager.add(mm);

  // listen for director-script requests from the child process
  mm.addMessageListener("debug:director-registry-request", handleChildRequest);

  // time to unsubscribe from the disconnected message manager
  DebuggerServer.once("disconnected-from-child:" + childID, handleMessageManagerDisconnected);

  function handleMessageManagerDisconnected(evt, { mm: disconnected_mm }) {
    ...
  }

The DebuggerServer emits "disconnected-from-child:CHILDID" events to give the actor modules the chance to cleanup their handlers registered on the disconnected message manager.

E10S setup flow

In the child process:

  • DebuggerServer loads an actor module
    • the actor module check DebuggerServer.isInChildProcess
      • the actor module calls the DebuggerServer.setupInParent helper
      • the DebuggerServer.setupInParent helper asks to the parent process to run the required setup
      • the actor module use the DebuggerServer.parentMessageManager.sendSyncMessage, DebuggerServer.parentMessageManager.addMessageListener helpers to send requests or to subscribe message handlers

In the parent process:

  • The DebuggerServer receives the DebuggerServer.setupInParent request
  • it tries to load the required module
  • it tries to call the mod[setupParent] method with the frame message manager and the childID in the json parameter { mm, childID }
    • the module setupParent helper use the mm to subscribe the messagemanager events
    • the module setupParent helper use the DebuggerServer object to subscribe once the "disconnected-from-child:CHILDID" event (needed to unsubscribe the messagemanager events)