From 3ea819fbef7e8c7b427430560ca37c34ee97e035 Mon Sep 17 00:00:00 2001 From: Alexandre Poirot Date: Thu, 8 Mar 2018 09:13:26 -0800 Subject: [PATCH] Bug 1444132 - Spawn a NetworkMonitorActor directly in the parent process. r=jryans This allows to create NetworkEventActor directly from the parent process and avoid most of the data being piped from the parent to the content processes. MozReview-Commit-ID: 8p3A5yl5eVB --HG-- extra : rebase_source : 49eb0406eff31b8262ac316884a4abd57512f6cf --- devtools/server/actors/moz.build | 1 + devtools/server/actors/network-event.js | 25 +++---- devtools/server/actors/network-monitor.js | 83 +++++++++++++++++++++++ devtools/server/actors/webconsole.js | 74 ++++++++++---------- devtools/shared/specs/moz.build | 1 + devtools/shared/specs/network-monitor.js | 15 ++++ 6 files changed, 148 insertions(+), 51 deletions(-) create mode 100644 devtools/server/actors/network-monitor.js create mode 100644 devtools/shared/specs/network-monitor.js diff --git a/devtools/server/actors/moz.build b/devtools/server/actors/moz.build index 8232dce7f4cc..a78392ba2920 100644 --- a/devtools/server/actors/moz.build +++ b/devtools/server/actors/moz.build @@ -44,6 +44,7 @@ DevToolsModules( 'layout.js', 'memory.js', 'network-event.js', + 'network-monitor.js', 'object.js', 'pause-scoped.js', 'perf.js', diff --git a/devtools/server/actors/network-event.js b/devtools/server/actors/network-event.js index ced4ba085ca7..196876d8dab5 100644 --- a/devtools/server/actors/network-event.js +++ b/devtools/server/actors/network-event.js @@ -12,16 +12,16 @@ const { LongStringActor } = require("devtools/server/actors/string"); * Creates an actor for a network event. * * @constructor - * @param object webConsoleActor - * The parent WebConsoleActor instance for this object. + * @param object netMonitorActor + * The parent NetworkMonitorActor instance for this object. */ const NetworkEventActor = protocol.ActorClassWithSpec(networkEventSpec, { - initialize(webConsoleActor) { + initialize(netMonitorActor) { // Necessary to get the events to work - protocol.Actor.prototype.initialize.call(this, webConsoleActor.conn); + protocol.Actor.prototype.initialize.call(this, netMonitorActor.conn); - this.webConsoleActor = webConsoleActor; - this.conn = this.webConsoleActor.conn; + this.netMonitorActor = netMonitorActor; + this.conn = this.netMonitorActor.conn; this._request = { method: null, @@ -72,22 +72,17 @@ const NetworkEventActor = protocol.ActorClassWithSpec(networkEventSpec, { * Releases this actor from the pool. */ destroy(conn) { - if (!this.webConsoleActor) { + if (!this.netMonitorActor) { return; } if (this._request.url) { - this.webConsoleActor._networkEventActorsByURL.delete(this._request.url); + this.netMonitorActor._networkEventActorsByURL.delete(this._request.url); } if (this.channel) { - this.webConsoleActor._netEvents.delete(this.channel); + this.netMonitorActor._netEvents.delete(this.channel); } - // Nullify webConsoleActor before calling releaseActor as it will recall this method - // To be removed once WebConsoleActor switches to protocol.js - const actor = this.webConsoleActor; - this.webConsoleActor = null; - actor.releaseActor(this); - + this.netMonitorActor = null; protocol.Actor.prototype.destroy.call(this, conn); }, diff --git a/devtools/server/actors/network-monitor.js b/devtools/server/actors/network-monitor.js new file mode 100644 index 000000000000..c5c8ae101f3f --- /dev/null +++ b/devtools/server/actors/network-monitor.js @@ -0,0 +1,83 @@ +/* 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"; + +const { Actor, ActorClassWithSpec } = require("devtools/shared/protocol"); +const { networkMonitorSpec } = require("devtools/shared/specs/network-monitor"); + +loader.lazyRequireGetter(this, "NetworkMonitor", "devtools/shared/webconsole/network-monitor", true); +loader.lazyRequireGetter(this, "NetworkEventActor", "devtools/server/actors/network-event", true); + +const NetworkMonitorActor = ActorClassWithSpec(networkMonitorSpec, { + _netEvents: new Map(), + _networkEventActorsByURL: new Map(), + + // NetworkMonitorActor is instanciated from WebConsoleActor.startListeners + // Either in the same process, for debugging service worker requests or when debugging + // the parent process itself and tracking chrome requests. + // Or in another process, for tracking content requests that are actually done in the + // parent process. + // `filters` argument either contains an `outerWindowID` attribute when this is used + // cross processes. Or a `window` attribute when instanciated in the same process. + // `parentID` is an optional argument, to be removed, that specify the ID of the Web + // console actor. This is used to fake emitting an event from it to prevent changing + // RDP behavior. + initialize(conn, filters, parentID) { + Actor.prototype.initialize.call(this, conn); + + this.parentID = parentID; + + // Immediately start watching for new request according to `filters`. + // NetworkMonitor will call `onNetworkEvent` method. + this.netMonitor = new NetworkMonitor(filters, this); + this.netMonitor.init(); + }, + + destroy() { + Actor.prototype.destroy.call(this); + + if (this.netMonitor) { + this.netMonitor.destroy(); + this.netMonitor = null; + } + }, + + getNetworkEventActor(channelId) { + let actor = this._netEvents.get(channelId); + if (actor) { + return actor; + } + + actor = new NetworkEventActor(this); + this.manage(actor); + + // map channel to actor so we can associate future events with it + this._netEvents.set(channelId, actor); + return actor; + }, + + // This method is called by NetworkMonitor instance when a new request is fired + onNetworkEvent(event) { + const { channelId } = event; + + const actor = this.getNetworkEventActor(channelId); + this._netEvents.set(channelId, actor); + + actor.init(event); + + this._networkEventActorsByURL.set(actor._request.url, actor); + + const packet = { + from: this.parentID, + type: "networkEvent", + eventActor: actor.form() + }; + + this.conn.send(packet); + return actor; + }, + +}); +exports.NetworkMonitorActor = NetworkMonitorActor; diff --git a/devtools/server/actors/webconsole.js b/devtools/server/actors/webconsole.js index c62ae7f0c47c..fc1649dece8c 100644 --- a/devtools/server/actors/webconsole.js +++ b/devtools/server/actors/webconsole.js @@ -19,8 +19,7 @@ const { createValueGrip, stringIsLong } = require("devtools/server/actors/object const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const ErrorDocs = require("devtools/server/actors/errordocs"); -loader.lazyRequireGetter(this, "NetworkMonitor", "devtools/shared/webconsole/network-monitor", true); -loader.lazyRequireGetter(this, "NetworkMonitorChild", "devtools/shared/webconsole/network-monitor", true); +loader.lazyRequireGetter(this, "NetworkMonitorActor", "devtools/server/actors/network-monitor", true); loader.lazyRequireGetter(this, "NetworkEventActor", "devtools/server/actors/network-event", true); loader.lazyRequireGetter(this, "ConsoleProgressListener", "devtools/shared/webconsole/network-monitor", true); loader.lazyRequireGetter(this, "StackTraceCollector", "devtools/shared/webconsole/network-monitor", true); @@ -288,16 +287,6 @@ WebConsoleActor.prototype = */ consoleAPIListener: null, - /** - * The NetworkMonitor instance. - */ - networkMonitor: null, - - /** - * The NetworkMonitor instance living in the same (child) process. - */ - networkMonitorChild: null, - /** * The ConsoleProgressListener instance. */ @@ -354,18 +343,21 @@ WebConsoleActor.prototype = this.consoleServiceListener.destroy(); this.consoleServiceListener = null; } + if (this.networkMonitorActor) { + this.networkMonitorActor.destroy(); + this.networkMonitorActor = null; + } + if (this.networkMonitorActorId) { + this.networkMonitorActorId = null; + } + if (this.networkMonitorChildActor) { + this.networkMonitorChildActor.destroy(); + this.networkMonitorChildActor = null; + } if (this.consoleAPIListener) { this.consoleAPIListener.destroy(); this.consoleAPIListener = null; } - if (this.networkMonitor) { - this.networkMonitor.destroy(); - this.networkMonitor = null; - } - if (this.networkMonitorChild) { - this.networkMonitorChild.destroy(); - this.networkMonitorChild = null; - } if (this.stackTraceCollector) { this.stackTraceCollector.destroy(); this.stackTraceCollector = null; @@ -575,7 +567,7 @@ WebConsoleActor.prototype = * @return object * The response object which holds the startedListeners array. */ - startListeners: function(request) { + startListeners: async function(request) { const startedListeners = []; const window = !this.parentActor.isRootActor ? this.window : null; let messageManager = null; @@ -623,7 +615,7 @@ WebConsoleActor.prototype = if (isWorker) { break; } - if (!this.networkMonitor) { + if (!this.networkMonitorActorId && !this.networkMonitorActor) { // Create a StackTraceCollector that's going to be shared both by // the NetworkMonitorChild (getting messages about requests from // parent) and by the NetworkMonitor that directly watches service @@ -634,16 +626,23 @@ WebConsoleActor.prototype = if (messageManager && processBoundary) { // Start a network monitor in the parent process to listen to // most requests than happen in parent - this.networkMonitor = - new NetworkMonitorChild(this.parentActor.outerWindowID, - messageManager, this.conn, this); - this.networkMonitor.init(); + this.networkMonitorActorId = await this.conn.spawnActorInParentProcess( + this.actorID, { + module: "devtools/server/actors/network-monitor", + constructor: "NetworkMonitorActor", + args: [ + { outerWindowID: this.parentActor.outerWindowID }, + this.actorID + ], + }); + // Spawn also one in the child to listen to service workers - this.networkMonitorChild = new NetworkMonitor({ window }, this); - this.networkMonitorChild.init(); + this.networkMonitorChildActor = new NetworkMonitorActor(this.conn, + { window }, + this.actorID); } else { - this.networkMonitor = new NetworkMonitor({ window }, this); - this.networkMonitor.init(); + this.networkMonitorActor = new NetworkMonitorActor(this.conn, { window }, + this.actorID); } } startedListeners.push(listener); @@ -743,13 +742,16 @@ WebConsoleActor.prototype = stoppedListeners.push(listener); break; case "NetworkActivity": - if (this.networkMonitor) { - this.networkMonitor.destroy(); - this.networkMonitor = null; + if (this.networkMonitorActor) { + this.networkMonitorActor.destroy(); + this.networkMonitorActor = null; } - if (this.networkMonitorChild) { - this.networkMonitorChild.destroy(); - this.networkMonitorChild = null; + if (this.networkMonitorActorId) { + this.networkMonitorActorId = null; + } + if (this.networkMonitorChildActor) { + this.networkMonitorChildActor.destroy(); + this.networkMonitorChildActor = null; } if (this.stackTraceCollector) { this.stackTraceCollector.destroy(); diff --git a/devtools/shared/specs/moz.build b/devtools/shared/specs/moz.build index dd87aeeca23f..43a2abcdf4c4 100644 --- a/devtools/shared/specs/moz.build +++ b/devtools/shared/specs/moz.build @@ -32,6 +32,7 @@ DevToolsModules( 'layout.js', 'memory.js', 'network-event.js', + 'network-monitor.js', 'node.js', 'object.js', 'perf.js', diff --git a/devtools/shared/specs/network-monitor.js b/devtools/shared/specs/network-monitor.js new file mode 100644 index 000000000000..1368b61b8571 --- /dev/null +++ b/devtools/shared/specs/network-monitor.js @@ -0,0 +1,15 @@ +/* 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"; + +const { generateActorSpec } = require("devtools/shared/protocol"); + +const networkMonitorSpec = generateActorSpec({ + typeName: "network-monitor", + + methods: {}, +}); + +exports.networkMonitorSpec = networkMonitorSpec;