зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1060093 - Implement toolbox to debug chrome of the content process. r=jryans
This commit is contained in:
Родитель
9df3eb992d
Коммит
64aef65e17
|
@ -513,6 +513,8 @@
|
|||
<menuitem id="menu_browserToolbox"
|
||||
observes="devtoolsMenuBroadcaster_BrowserToolbox"
|
||||
accesskey="&browserToolboxMenu.accesskey;"/>
|
||||
<menuitem id="menu_browserContentToolbox"
|
||||
observes="devtoolsMenuBroadcaster_BrowserContentToolbox"/>
|
||||
<menuitem id="menu_browserConsole"
|
||||
observes="devtoolsMenuBroadcaster_BrowserConsole"
|
||||
accesskey="&browserConsoleCmd.accesskey;"/>
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
<command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/>
|
||||
<command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserContentToolbox" oncommand="gDevToolsBrowser.openContentProcessToolbox();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
|
||||
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
|
||||
|
@ -207,6 +208,9 @@
|
|||
<broadcaster id="devtoolsMenuBroadcaster_BrowserToolbox"
|
||||
label="&browserToolboxMenu.label;"
|
||||
command="Tools:BrowserToolbox"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_BrowserContentToolbox"
|
||||
label="&browserContentToolboxMenu.label;"
|
||||
command="Tools:BrowserContentToolbox"/>
|
||||
<broadcaster id="devtoolsMenuBroadcaster_BrowserConsole"
|
||||
label="&browserConsoleCmd.label;"
|
||||
key="key_browserConsole"
|
||||
|
|
|
@ -20,11 +20,18 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
|
|||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
|
||||
"resource:///modules/CustomizableUI.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
|
||||
"resource://gre/modules/devtools/dbg-server.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
|
||||
"resource://gre/modules/devtools/dbg-client.jsm");
|
||||
|
||||
const EventEmitter = devtools.require("devtools/toolkit/event-emitter");
|
||||
const FORBIDDEN_IDS = new Set(["toolbox", ""]);
|
||||
const MAX_ORDINAL = 99;
|
||||
|
||||
const bundle = Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
|
||||
|
||||
/**
|
||||
* The method name to use for ES6 iteration. If symbols are enabled in this
|
||||
* build, use Symbol.iterator; otherwise "@@iterator".
|
||||
|
@ -593,6 +600,7 @@ let gDevToolsBrowser = {
|
|||
let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled &&
|
||||
Services.prefs.getBoolPref("devtools.debugger.chrome-enabled");
|
||||
toggleCmd("Tools:BrowserToolbox", remoteEnabled);
|
||||
toggleCmd("Tools:BrowserContentToolbox", remoteEnabled && win.gMultiProcessBrowser);
|
||||
|
||||
// Enable Error Console?
|
||||
let consoleEnabled = Services.prefs.getBoolPref("devtools.errorconsole.enabled");
|
||||
|
@ -688,6 +696,61 @@ let gDevToolsBrowser = {
|
|||
}
|
||||
},
|
||||
|
||||
_getContentProcessTarget: function () {
|
||||
// Create a DebuggerServer in order to connect locally to it
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
let client = new DebuggerClient(transport);
|
||||
|
||||
let deferred = promise.defer();
|
||||
client.connect(() => {
|
||||
client.mainRoot.listProcesses(response => {
|
||||
// Do nothing if there is only one process, the parent process.
|
||||
let contentProcesses = response.processes.filter(p => (!p.parent));
|
||||
if (contentProcesses.length < 1) {
|
||||
let msg = bundle.GetStringFromName("toolbox.noContentProcess.message");
|
||||
Services.prompt.alert(null, "", msg);
|
||||
deferred.reject("No content processes available.");
|
||||
return;
|
||||
}
|
||||
// Otherwise, arbitrary connect to the unique content process.
|
||||
client.attachProcess(contentProcesses[0].id)
|
||||
.then(response => {
|
||||
let options = {
|
||||
form: response.form,
|
||||
client: client,
|
||||
chrome: true
|
||||
};
|
||||
return devtools.TargetFactory.forRemoteTab(options);
|
||||
})
|
||||
.then(target => {
|
||||
// Ensure closing the connection in order to cleanup
|
||||
// the debugger client and also the server created in the
|
||||
// content process
|
||||
target.on("close", () => {
|
||||
client.close();
|
||||
});
|
||||
deferred.resolve(target);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
openContentProcessToolbox: function () {
|
||||
this._getContentProcessTarget()
|
||||
.then(target => {
|
||||
// Display a new toolbox, in a new window, with debugger by default
|
||||
return gDevTools.showToolbox(target, "jsdebugger",
|
||||
devtools.Toolbox.HostType.WINDOW);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Install WebIDE widget
|
||||
*/
|
||||
|
|
|
@ -268,6 +268,11 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
|||
<!ENTITY browserToolboxMenu.label "Browser Toolbox">
|
||||
<!ENTITY browserToolboxMenu.accesskey "e">
|
||||
|
||||
<!-- LOCALIZATION NOTE (browserContentToolboxMenu.label): This is the label for the
|
||||
- application menu item that opens the browser content toolbox UI in the Tools menu.
|
||||
- This toolbox allows to debug the chrome of the content process in multiprocess builds. -->
|
||||
<!ENTITY browserContentToolboxMenu.label "Browser Content Toolbox">
|
||||
|
||||
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
|
||||
<!ENTITY devToolbarMenu.label "Developer Toolbar">
|
||||
<!ENTITY devToolbarMenu.accesskey "v">
|
||||
|
|
|
@ -78,3 +78,8 @@ options.darkTheme.label=Dark theme
|
|||
# LOCALIZATION NOTE (options.lightTheme.label)
|
||||
# Used as a label for light theme
|
||||
options.lightTheme.label=Light theme
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.noContentProcess.message)
|
||||
# Used as a message in the alert displayed when trying to open a browser
|
||||
# content toolbox and there is no content process running
|
||||
toolbox.noContentProcess.message=No content process running.
|
||||
|
|
|
@ -25,6 +25,7 @@ ContentProcessSingleton.prototype = {
|
|||
case "app-startup": {
|
||||
Services.obs.addObserver(this, "console-api-log-event", false);
|
||||
Services.obs.addObserver(this, "xpcom-shutdown", false);
|
||||
cpmm.addMessageListener("DevTools:InitDebuggerServer", this);
|
||||
break;
|
||||
}
|
||||
case "console-api-log-event": {
|
||||
|
@ -56,9 +57,19 @@ ContentProcessSingleton.prototype = {
|
|||
case "xpcom-shutdown":
|
||||
Services.obs.removeObserver(this, "console-api-log-event");
|
||||
Services.obs.removeObserver(this, "xpcom-shutdown");
|
||||
cpmm.removeMessageListener("DevTools:InitDebuggerServer", this);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
receiveMessage: function (message) {
|
||||
// load devtools component on-demand
|
||||
// Only reply if we are in a real content process
|
||||
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
|
||||
let {init} = Cu.import("resource://gre/modules/devtools/content-server.jsm", {});
|
||||
init(message);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentProcessSingleton]);
|
||||
|
|
|
@ -5191,6 +5191,20 @@
|
|||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'listAddons' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_LOCAL_LISTPROCESSES_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "10000",
|
||||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'listProcesses' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_REMOTE_LISTPROCESSES_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "10000",
|
||||
"n_buckets": "1000",
|
||||
"description": "The time (in milliseconds) that it took a 'listProcesses' request to go round trip."
|
||||
},
|
||||
"DEVTOOLS_DEBUGGER_RDP_LOCAL_DELETE_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
|
|
@ -594,6 +594,21 @@ DebuggerClient.prototype = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach to a process in order to get the form of a ChildProcessActor.
|
||||
*
|
||||
* @param string aId
|
||||
* The ID for the process to attach (returned by `listProcesses`).
|
||||
*/
|
||||
attachProcess: function (aId) {
|
||||
let packet = {
|
||||
to: 'root',
|
||||
type: 'attachProcess',
|
||||
id: aId
|
||||
}
|
||||
return this.request(packet);
|
||||
},
|
||||
|
||||
/**
|
||||
* Release an object actor.
|
||||
*
|
||||
|
@ -1292,6 +1307,15 @@ RootClient.prototype = {
|
|||
listAddons: DebuggerClient.requester({ type: "listAddons" },
|
||||
{ telemetry: "LISTADDONS" }),
|
||||
|
||||
/**
|
||||
* List the running processes.
|
||||
*
|
||||
* @param function aOnResponse
|
||||
* Called with the response packet.
|
||||
*/
|
||||
listProcesses: DebuggerClient.requester({ type: "listProcesses" },
|
||||
{ telemetry: "LISTPROCESSES" }),
|
||||
|
||||
/**
|
||||
* Description of protocol's actors and methods.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/* 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 { Cc, Ci, Cu } = require("chrome");
|
||||
|
||||
const { ChromeDebuggerActor } = require("devtools/server/actors/script");
|
||||
const { WebConsoleActor } = require("devtools/server/actors/webconsole");
|
||||
const makeDebugger = require("devtools/server/actors/utils/make-debugger");
|
||||
const { ActorPool } = require("devtools/server/main");
|
||||
const Services = require("Services");
|
||||
|
||||
function ChildProcessActor(aConnection) {
|
||||
this.conn = aConnection;
|
||||
this._contextPool = new ActorPool(this.conn);
|
||||
this.conn.addActorPool(this._contextPool);
|
||||
this._threadActor = null;
|
||||
|
||||
// Use a see-everything debugger
|
||||
this.makeDebugger = makeDebugger.bind(null, {
|
||||
findDebuggees: dbg => dbg.findAllGlobals(),
|
||||
shouldAddNewGlobalAsDebuggee: global => true
|
||||
});
|
||||
|
||||
// Scope into which the webconsole executes:
|
||||
// An empty sandbox with chrome privileges
|
||||
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]
|
||||
.createInstance(Ci.nsIPrincipal);
|
||||
let sandbox = Cu.Sandbox(systemPrincipal);
|
||||
this._consoleScope = sandbox;
|
||||
}
|
||||
exports.ChildProcessActor = ChildProcessActor;
|
||||
|
||||
ChildProcessActor.prototype = {
|
||||
actorPrefix: "process",
|
||||
|
||||
get isRootActor() true,
|
||||
|
||||
get exited() {
|
||||
return !this._contextPool;
|
||||
},
|
||||
|
||||
get url() {
|
||||
return undefined;
|
||||
},
|
||||
|
||||
get window() {
|
||||
return this._consoleScope;
|
||||
},
|
||||
|
||||
form: function() {
|
||||
if (!this._consoleActor) {
|
||||
this._consoleActor = new WebConsoleActor(this.conn, this);
|
||||
this._contextPool.addActor(this._consoleActor);
|
||||
}
|
||||
|
||||
if (!this._threadActor) {
|
||||
this._threadActor = new ChromeDebuggerActor(this.conn, this);
|
||||
this._contextPool.addActor(this._threadActor);
|
||||
}
|
||||
|
||||
return {
|
||||
actor: this.actorID,
|
||||
name: "Content process",
|
||||
|
||||
consoleActor: this._consoleActor.actorID,
|
||||
chromeDebugger: this._threadActor.actorID,
|
||||
|
||||
traits: {
|
||||
highlightable: false,
|
||||
networkMonitor: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
disconnect: function() {
|
||||
this.conn.removeActorPool(this._contextPool);
|
||||
this._contextPool = null;
|
||||
},
|
||||
|
||||
preNest: function() {
|
||||
// TODO: freeze windows
|
||||
// window mediator doesn't work in child.
|
||||
// it doesn't throw, but doesn't return any window
|
||||
},
|
||||
|
||||
postNest: function() {
|
||||
},
|
||||
};
|
||||
|
||||
ChildProcessActor.prototype.requestTypes = {
|
||||
};
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { Ci, Cu } = require("chrome");
|
||||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const Services = require("Services");
|
||||
const { ActorPool, appendExtraActors, createExtraActors } = require("devtools/server/actors/common");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
|
@ -18,6 +18,10 @@ DevToolsUtils.defineLazyGetter(this, "StyleSheetActor", () => {
|
|||
return require("devtools/server/actors/stylesheets").StyleSheetActor;
|
||||
});
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "ppmm", () => {
|
||||
return Cc["@mozilla.org/parentprocessmessagemanager;1"].getService(Ci.nsIMessageBroadcaster);
|
||||
});
|
||||
|
||||
/* Root actor for the remote debugging protocol. */
|
||||
|
||||
/**
|
||||
|
@ -358,6 +362,28 @@ RootActor.prototype = {
|
|||
this._parameters.addonList.onListChanged = null;
|
||||
},
|
||||
|
||||
onListProcesses: function () {
|
||||
let processes = [];
|
||||
for (let i = 0; i < ppmm.childCount; i++) {
|
||||
processes.push({
|
||||
id: i, // XXX: may not be a perfect id, but process message manager doesn't expose anything...
|
||||
parent: i == 0, // XXX Weak, but appear to be stable
|
||||
tabCount: undefined, // TODO: exposes process message manager on frameloaders in order to compute this
|
||||
});
|
||||
}
|
||||
return { processes: processes };
|
||||
},
|
||||
|
||||
onAttachProcess: function (aRequest) {
|
||||
let mm = ppmm.getChildAt(aRequest.id);
|
||||
if (!mm) {
|
||||
return { error: "noProcess",
|
||||
message: "There is no process with id '" + aRequest.id + "'." };
|
||||
}
|
||||
return DebuggerServer.connectToContent(this.conn, mm)
|
||||
.then(form => ({ form: form }));
|
||||
},
|
||||
|
||||
/* This is not in the spec, but it's used by tests. */
|
||||
onEcho: function (aRequest) {
|
||||
/*
|
||||
|
@ -431,6 +457,8 @@ RootActor.prototype = {
|
|||
RootActor.prototype.requestTypes = {
|
||||
"listTabs": RootActor.prototype.onListTabs,
|
||||
"listAddons": RootActor.prototype.onListAddons,
|
||||
"listProcesses": RootActor.prototype.onListProcesses,
|
||||
"attachProcess": RootActor.prototype.onAttachProcess,
|
||||
"echo": RootActor.prototype.onEcho,
|
||||
"protocolDescription": RootActor.prototype.onProtocolDescription
|
||||
};
|
||||
|
|
|
@ -559,13 +559,15 @@ WebConsoleActor.prototype =
|
|||
startedListeners.push(listener);
|
||||
break;
|
||||
case "FileActivity":
|
||||
if (!this.consoleProgressListener) {
|
||||
this.consoleProgressListener =
|
||||
new ConsoleProgressListener(this.window, this);
|
||||
if (this.window instanceof Ci.nsIDOMWindow) {
|
||||
if (!this.consoleProgressListener) {
|
||||
this.consoleProgressListener =
|
||||
new ConsoleProgressListener(this.window, this);
|
||||
}
|
||||
this.consoleProgressListener.startMonitor(this.consoleProgressListener.
|
||||
MONITOR_FILE_ACTIVITY);
|
||||
startedListeners.push(listener);
|
||||
}
|
||||
this.consoleProgressListener.startMonitor(this.consoleProgressListener.
|
||||
MONITOR_FILE_ACTIVITY);
|
||||
startedListeners.push(listener);
|
||||
break;
|
||||
case "ReflowActivity":
|
||||
if (!this.consoleReflowListener) {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* 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 Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cu = Components.utils;
|
||||
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
const { DevToolsLoader } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["init"];
|
||||
|
||||
let started = false;
|
||||
|
||||
function init(msg) {
|
||||
if (started) {
|
||||
return;
|
||||
}
|
||||
started = true;
|
||||
|
||||
// Init a custom, invisible DebuggerServer, in order to not pollute
|
||||
// the debugger with all devtools modules, nor break the debugger itself with using it
|
||||
// in the same process.
|
||||
let devtools = new DevToolsLoader();
|
||||
devtools.invisibleToDebugger = true;
|
||||
devtools.main("devtools/server/main");
|
||||
let { DebuggerServer, ActorPool } = devtools;
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
}
|
||||
|
||||
// In case of apps being loaded in parent process, DebuggerServer is already
|
||||
// initialized, but child specific actors are not registered.
|
||||
// Otherwise, for child process, we need to load actors the first
|
||||
// time we load child.js
|
||||
DebuggerServer.addChildActors();
|
||||
|
||||
let mm = msg.target;
|
||||
mm.QueryInterface(Ci.nsISyncMessageSender);
|
||||
let prefix = msg.data.prefix;
|
||||
|
||||
// Connect both parent/child processes debugger servers RDP via message managers
|
||||
let conn = DebuggerServer.connectToParent(prefix, mm);
|
||||
|
||||
let { ChildProcessActor } = devtools.require("devtools/server/actors/child-process");
|
||||
let actor = new ChildProcessActor(conn);
|
||||
let actorPool = new ActorPool(conn);
|
||||
actorPool.addActor(actor);
|
||||
conn.addActorPool(actorPool);
|
||||
|
||||
let response = {actor: actor.form()};
|
||||
mm.sendAsyncMessage("debug:content-process-actor", response);
|
||||
|
||||
mm.addMessageListener("debug:content-process-destroy", function onDestroy() {
|
||||
mm.removeMessageListener("debug:content-process-destroy", onDestroy);
|
||||
|
||||
DebuggerServer.destroy();
|
||||
started = false;
|
||||
});
|
||||
}
|
|
@ -704,6 +704,69 @@ var DebuggerServer = {
|
|||
return this._onConnection(transport, aPrefix, true);
|
||||
},
|
||||
|
||||
connectToContent: function (aConnection, aMm) {
|
||||
let deferred = defer();
|
||||
|
||||
let prefix = aConnection.allocID("content-process");
|
||||
let actor, childTransport;
|
||||
|
||||
aMm.addMessageListener("debug:content-process-actor", function listener(msg) {
|
||||
// Arbitrarily choose the first content process to reply
|
||||
// XXX: This code needs to be updated if we use more than one content process
|
||||
aMm.removeMessageListener("debug:content-process-actor", listener);
|
||||
|
||||
// Pipe Debugger message from/to parent/child via the message manager
|
||||
childTransport = new ChildDebuggerTransport(aMm, prefix);
|
||||
childTransport.hooks = {
|
||||
onPacket: aConnection.send.bind(aConnection),
|
||||
onClosed: function () {}
|
||||
};
|
||||
childTransport.ready();
|
||||
|
||||
aConnection.setForwarding(prefix, childTransport);
|
||||
|
||||
dumpn("establishing forwarding for process with prefix " + prefix);
|
||||
|
||||
actor = msg.json.actor;
|
||||
|
||||
deferred.resolve(actor);
|
||||
});
|
||||
|
||||
aMm.sendAsyncMessage("DevTools:InitDebuggerServer", {
|
||||
prefix: prefix
|
||||
});
|
||||
|
||||
function onDisconnect() {
|
||||
Services.obs.removeObserver(onMessageManagerDisconnect, "message-manager-disconnect");
|
||||
events.off(aConnection, "closed", onDisconnect);
|
||||
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;
|
||||
aConnection.cancelForwarding(prefix);
|
||||
|
||||
// ... and notify the child process to clean the tab actors.
|
||||
try {
|
||||
aMm.sendAsyncMessage("debug:content-process-destroy");
|
||||
} catch(e) {}
|
||||
}
|
||||
}
|
||||
|
||||
let onMessageManagerDisconnect = DevToolsUtils.makeInfallible(function (subject, topic, data) {
|
||||
if (subject == aMm) {
|
||||
onDisconnect();
|
||||
aConnection.send({ from: actor.actor, type: "tabDetached" });
|
||||
}
|
||||
}).bind(this);
|
||||
Services.obs.addObserver(onMessageManagerDisconnect,
|
||||
"message-manager-disconnect", false);
|
||||
|
||||
events.on(aConnection, "closed", onDisconnect);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Connect to a child process.
|
||||
*
|
||||
|
|
|
@ -21,6 +21,7 @@ SOURCES += [
|
|||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
EXTRA_JS_MODULES.devtools += [
|
||||
'content-server.jsm',
|
||||
'dbg-server.jsm',
|
||||
]
|
||||
|
||||
|
@ -34,6 +35,7 @@ EXTRA_JS_MODULES.devtools.server += [
|
|||
EXTRA_JS_MODULES.devtools.server.actors += [
|
||||
'actors/call-watcher.js',
|
||||
'actors/canvas.js',
|
||||
'actors/child-process.js',
|
||||
'actors/childtab.js',
|
||||
'actors/common.js',
|
||||
'actors/csscoverage.js',
|
||||
|
|
|
@ -73,3 +73,5 @@ skip-if = buildapp == 'mulet'
|
|||
[test_preference.html]
|
||||
[test_connectToChild.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_attachProcess.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
<SDOCTYPv HTM.>
|
||||
<html>
|
||||
<!--
|
||||
Bug 1060093 - Test DebuggerServer.attachProcess
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mozilla Bug</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.8">
|
||||
|
||||
let Cu = Components.utils;
|
||||
let Cc = Components.classes;
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
// Always log packets when running tests.
|
||||
["devtools.debugger.log", true],
|
||||
["dom.mozBrowserFramesEnabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
// Create a remote iframe with a message manager
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.mozbrowser = true;
|
||||
iframe.setAttribute("remote", "true");
|
||||
iframe.setAttribute("src", "data:text/html,foo");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
let mm = iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
|
||||
|
||||
// Instantiate a minimal server
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init(function () { return true; });
|
||||
}
|
||||
if (!DebuggerServer.createRootActor) {
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
|
||||
function firstClient() {
|
||||
// Fake a first connection to the content process
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
let client = new DebuggerClient(transport);
|
||||
client.connect(() => {
|
||||
client.mainRoot.listProcesses(response => {
|
||||
ok(response.processes.length >= 2, "Got at least the parent process and one child");
|
||||
|
||||
// Connect to the first content processe available
|
||||
let content = response.processes.filter(p => (!p.parent))[0];
|
||||
|
||||
client.attachProcess(content.id).then(response => {
|
||||
let actor = response.form;
|
||||
ok(actor.consoleActor, "Got the console actor");
|
||||
ok(actor.chromeDebugger, "Got the thread actor");
|
||||
|
||||
// Ensure sending at least one request to an actor...
|
||||
client.request({
|
||||
to: actor.consoleActor,
|
||||
type: "evaluateJS",
|
||||
text: "var a = 42; a"
|
||||
}, function (response) {
|
||||
ok(response.result, 42, "console.eval worked");
|
||||
|
||||
client.close(cleanup);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
DebuggerServer.destroy();
|
||||
iframe.remove();
|
||||
SimpleTest.finish()
|
||||
}
|
||||
|
||||
firstClient();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче