/* 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/. */ "use strict"; var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); var { dumpn } = DevToolsUtils; var { createContentProcessSessionContext, } = require("resource://devtools/server/actors/watcher/session-context.js"); loader.lazyRequireGetter( this, "ChildDebuggerTransport", "resource://devtools/shared/transport/child-transport.js", true ); const CONTENT_PROCESS_SERVER_STARTUP_SCRIPT = "resource://devtools/server/startup/content-process.js"; loader.lazyRequireGetter( this, "EventEmitter", "resource://devtools/shared/event-emitter.js" ); /** * Start a DevTools server in a content process (representing the entire process, not * just a single frame) and add it as a child server for an active connection. */ function connectToContentProcess(connection, mm, onDestroy) { return new Promise(resolve => { const prefix = connection.allocID("content-process"); let actor, childTransport; mm.addMessageListener( "debug:content-process-actor", function listener(msg) { // Ignore actors being created by a Watcher actor, // they will be handled by devtools/server/watcher/target-helpers/process.js if (msg.watcherActorID) { return; } mm.removeMessageListener("debug:content-process-actor", listener); // Pipe Debugger message from/to parent/child via the message manager childTransport = new ChildDebuggerTransport(mm, prefix); childTransport.hooks = { onPacket: connection.send.bind(connection), }; childTransport.ready(); connection.setForwarding(prefix, childTransport); dumpn(`Start forwarding for process with prefix ${prefix}`); actor = msg.json.actor; resolve(actor); } ); // Load the content process server startup script only once. const isContentProcessServerStartupScripLoaded = Services.ppmm .getDelayedProcessScripts() .some(([uri]) => uri === CONTENT_PROCESS_SERVER_STARTUP_SCRIPT); if (!isContentProcessServerStartupScripLoaded) { // Load the process script that will receive the debug:init-content-server message Services.ppmm.loadProcessScript( CONTENT_PROCESS_SERVER_STARTUP_SCRIPT, true ); } // Send a message to the content process server startup script to forward it the // prefix. mm.sendAsyncMessage("debug:init-content-server", { prefix, // This connector is only used for the Browser Content Toolbox, // when creating the content process target from the Process Descriptor. sessionContext: createContentProcessSessionContext(), }); function onClose() { Services.obs.removeObserver( onMessageManagerClose, "message-manager-close" ); EventEmitter.off(connection, "closed", onClose); if (childTransport) { // If we have a child transport, the actor has already // been created. We need to stop using this message manager. childTransport.close(); childTransport = null; connection.cancelForwarding(prefix); // ... and notify the child process to clean the target-scoped actors. try { mm.sendAsyncMessage("debug:content-process-disconnect", { prefix }); } catch (e) { // Nothing to do } } if (onDestroy) { onDestroy(mm); } } const onMessageManagerClose = DevToolsUtils.makeInfallible( (subject, topic, data) => { if (subject == mm) { onClose(); } } ); Services.obs.addObserver(onMessageManagerClose, "message-manager-close"); EventEmitter.on(connection, "closed", onClose); }); } exports.connectToContentProcess = connectToContentProcess;