1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
/* 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";
/*
* Module that listens for requests to start a `DevToolsServer` for an entire content
* process. Loaded into content processes by the main process during
* content-process-connector.js' `connectToContentProcess` via the process
* script `content-process.js`.
*
* The actual server startup itself is in this JSM so that code can be cached.
*/
/* exported initContentProcessTarget */
const EXPORTED_SYMBOLS = ["initContentProcessTarget"];
let gLoader;
function setupServer(mm) {
// Prevent spawning multiple server per process, even if the caller call us
// multiple times
if (gLoader) {
return gLoader;
}
// Lazy load Loader.jsm to prevent loading any devtools dependency too early.
const { DevToolsLoader } = ChromeUtils.import(
"resource://devtools/shared/Loader.jsm"
);
// Init a custom, invisible DevToolsServer, in order to not pollute the
// debugger with all devtools modules, nor break the debugger itself with
// using it in the same process.
gLoader = new DevToolsLoader({
invisibleToDebugger: true,
});
const { DevToolsServer } = gLoader.require("devtools/server/devtools-server");
DevToolsServer.init();
// For browser content toolbox, we do need a regular root actor and all tab
// actors, but don't need all the "browser actors" that are only useful when
// debugging the parent process via the browser toolbox.
DevToolsServer.registerActors({ root: true, target: true });
// Destroy the server once its last connection closes. Note that multiple frame
// scripts may be running in parallel and reuse the same server.
function destroyServer() {
// Only destroy the server if there is no more connections to it. It may be used
// to debug the same process from another client.
if (DevToolsServer.hasConnection()) {
return;
}
DevToolsServer.off("connectionchange", destroyServer);
DevToolsServer.destroy();
gLoader.destroy();
gLoader = null;
}
DevToolsServer.on("connectionchange", destroyServer);
return gLoader;
}
function initContentProcessTarget(msg) {
const mm = msg.target;
const prefix = msg.data.prefix;
const watcherActorID = msg.data.watcherActorID;
// Setup a server if none started yet
const loader = setupServer(mm);
// Connect both parent/child processes devtools servers RDP via message
// managers
const { DevToolsServer } = loader.require("devtools/server/devtools-server");
const conn = DevToolsServer.connectToParent(prefix, mm);
conn.parentMessageManager = mm;
const { ContentProcessTargetActor } = loader.require(
"devtools/server/actors/targets/content-process"
);
const actor = new ContentProcessTargetActor(conn);
actor.manage(actor);
const response = { watcherActorID, prefix, actor: actor.form() };
mm.sendAsyncMessage("debug:content-process-actor", response);
// Clean up things when the client disconnects
mm.addMessageListener("debug:content-process-disconnect", function onDestroy(
message
) {
if (message.data.prefix != prefix) {
// Several copies of this process script can be running for a single process if
// we are debugging the same process from multiple clients.
// If this disconnect request doesn't match a connection known here, ignore it.
return;
}
mm.removeMessageListener("debug:content-process-disconnect", onDestroy);
// Call DevToolsServerConnection.close to destroy all child actors. It should end up
// calling DevToolsServerConnection.onClosed that would actually cleanup all actor
// pools.
conn.close();
});
return {
actor,
connection: conn,
};
}
|