content-process-connector.js (3953B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 var DevToolsUtils = require("resource://devtools/shared/DevToolsUtils.js"); 8 var { dumpn } = DevToolsUtils; 9 var { 10 createContentProcessSessionContext, 11 } = require("resource://devtools/server/actors/watcher/session-context.js"); 12 13 loader.lazyRequireGetter( 14 this, 15 "ChildDebuggerTransport", 16 "resource://devtools/shared/transport/child-transport.js", 17 true 18 ); 19 20 const CONTENT_PROCESS_SERVER_STARTUP_SCRIPT = 21 "resource://devtools/server/startup/content-process.js"; 22 23 loader.lazyRequireGetter( 24 this, 25 "EventEmitter", 26 "resource://devtools/shared/event-emitter.js" 27 ); 28 29 /** 30 * Start a DevTools server in a content process (representing the entire process, not 31 * just a single frame) and add it as a child server for an active connection. 32 */ 33 function connectToContentProcess(connection, mm, onDestroy) { 34 return new Promise(resolve => { 35 const prefix = connection.allocID("content-process"); 36 let actor, childTransport; 37 38 mm.addMessageListener( 39 "debug:content-process-actor", 40 function listener(msg) { 41 // Ignore actors being created by a Watcher actor, 42 // they will be handled by devtools/server/watcher/target-helpers/process.js 43 if (msg.watcherActorID) { 44 return; 45 } 46 mm.removeMessageListener("debug:content-process-actor", listener); 47 48 // Pipe Debugger message from/to parent/child via the message manager 49 childTransport = new ChildDebuggerTransport(mm, prefix); 50 childTransport.hooks = { 51 onPacket: connection.send.bind(connection), 52 }; 53 childTransport.ready(); 54 55 connection.setForwarding(prefix, childTransport); 56 57 dumpn(`Start forwarding for process with prefix ${prefix}`); 58 59 actor = msg.json.actor; 60 61 resolve(actor); 62 } 63 ); 64 65 // Load the content process server startup script only once. 66 const isContentProcessServerStartupScripLoaded = Services.ppmm 67 .getDelayedProcessScripts() 68 .some(([uri]) => uri === CONTENT_PROCESS_SERVER_STARTUP_SCRIPT); 69 if (!isContentProcessServerStartupScripLoaded) { 70 // Load the process script that will receive the debug:init-content-server message 71 Services.ppmm.loadProcessScript( 72 CONTENT_PROCESS_SERVER_STARTUP_SCRIPT, 73 true 74 ); 75 } 76 77 // Send a message to the content process server startup script to forward it the 78 // prefix. 79 mm.sendAsyncMessage("debug:init-content-server", { 80 prefix, 81 // This connector is only used for the Browser Content Toolbox, 82 // when creating the content process target from the Process Descriptor. 83 sessionContext: createContentProcessSessionContext(), 84 }); 85 86 function onClose() { 87 Services.obs.removeObserver( 88 onMessageManagerClose, 89 "message-manager-close" 90 ); 91 connection.off("closed", onClose); 92 if (childTransport) { 93 // If we have a child transport, the actor has already 94 // been created. We need to stop using this message manager. 95 childTransport.close(); 96 childTransport = null; 97 connection.cancelForwarding(prefix); 98 99 // ... and notify the child process to clean the target-scoped actors. 100 try { 101 mm.sendAsyncMessage("debug:content-process-disconnect", { prefix }); 102 } catch (e) { 103 // Nothing to do 104 } 105 } 106 107 if (onDestroy) { 108 onDestroy(mm); 109 } 110 } 111 112 const onMessageManagerClose = DevToolsUtils.makeInfallible(subject => { 113 if (subject == mm) { 114 onClose(); 115 } 116 }); 117 Services.obs.addObserver(onMessageManagerClose, "message-manager-close"); 118 119 connection.on("closed", onClose); 120 }); 121 } 122 123 exports.connectToContentProcess = connectToContentProcess;