зеркало из https://github.com/mozilla/gecko-dev.git
Bug 966991 - Ensure cleaning up child processes tab actors when disconnecting. r=jryans
This commit is contained in:
Родитель
81be981df4
Коммит
052c4e3e3d
|
@ -24,12 +24,14 @@ let chromeGlobal = this;
|
|||
// time we load child.js
|
||||
DebuggerServer.addChildActors();
|
||||
|
||||
let conn;
|
||||
|
||||
let onConnect = DevToolsUtils.makeInfallible(function (msg) {
|
||||
removeMessageListener("debug:connect", onConnect);
|
||||
|
||||
let mm = msg.target;
|
||||
|
||||
let conn = DebuggerServer.connectToParent(msg.data.prefix, mm);
|
||||
conn = DebuggerServer.connectToParent(msg.data.prefix, mm);
|
||||
|
||||
let actor = new DebuggerServer.ContentActor(conn, chromeGlobal);
|
||||
let actorPool = new ActorPool(conn);
|
||||
|
@ -40,4 +42,15 @@ let chromeGlobal = this;
|
|||
});
|
||||
|
||||
addMessageListener("debug:connect", onConnect);
|
||||
|
||||
let onDisconnect = DevToolsUtils.makeInfallible(function (msg) {
|
||||
removeMessageListener("debug:disconnect", onDisconnect);
|
||||
|
||||
// Call DebuggerServerConnection.close to destroy all child actors
|
||||
// (It should end up calling DebuggerServerConnection.onClosed
|
||||
// that would actually cleanup all actor pools)
|
||||
conn.close();
|
||||
conn = null;
|
||||
});
|
||||
addMessageListener("debug:disconnect", onDisconnect);
|
||||
})();
|
||||
|
|
|
@ -59,6 +59,7 @@ function loadSubScript(aURL)
|
|||
}
|
||||
}
|
||||
|
||||
let events = require("sdk/event/core");
|
||||
let {defer, resolve, reject, promised, all} = require("sdk/core/promise");
|
||||
this.defer = defer;
|
||||
this.resolve = resolve;
|
||||
|
@ -571,6 +572,7 @@ var DebuggerServer = {
|
|||
// 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);
|
||||
} else {
|
||||
// Otherwise, the app has been closed before the actor
|
||||
|
@ -594,6 +596,20 @@ var DebuggerServer = {
|
|||
Services.obs.addObserver(onMessageManagerDisconnect,
|
||||
"message-manager-disconnect", false);
|
||||
|
||||
events.once(aConnection, "closed", () => {
|
||||
if (childTransport) {
|
||||
// When the client disconnects, we have to unplug the dedicated
|
||||
// ChildDebuggerTransport...
|
||||
childTransport.close();
|
||||
childTransport = null;
|
||||
aConnection.cancelForwarding(prefix);
|
||||
|
||||
// ... and notify the child process to clean the tab actors.
|
||||
mm.sendAsyncMessage("debug:disconnect");
|
||||
}
|
||||
Services.obs.removeObserver(onMessageManagerDisconnect, "message-manager-disconnect");
|
||||
});
|
||||
|
||||
mm.sendAsyncMessage("debug:connect", { prefix: prefix });
|
||||
|
||||
return deferred.promise;
|
||||
|
@ -1156,6 +1172,11 @@ DebuggerServerConnection.prototype = {
|
|||
*/
|
||||
onClosed: function DSC_onClosed(aStatus) {
|
||||
dumpn("Cleaning up connection.");
|
||||
if (!this._actorPool) {
|
||||
// Ignore this call if the connection is already closed.
|
||||
return;
|
||||
}
|
||||
events.emit(this, "closed", aStatus);
|
||||
|
||||
this._actorPool.cleanup();
|
||||
this._actorPool = null;
|
||||
|
|
|
@ -43,3 +43,4 @@ support-files =
|
|||
[test_inspector_getImageData.html]
|
||||
[test_memory.html]
|
||||
[test_preference.html]
|
||||
[test_connectToChild.html]
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
<SDOCTYPv HTM.>
|
||||
<html>
|
||||
<!--
|
||||
Bug 966991 - Test DebuggerServer.connectToChild
|
||||
-->
|
||||
<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();
|
||||
|
||||
// Always log packets when running tests.
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["devtools.debugger.log", true]
|
||||
]
|
||||
}, runTests);
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
// Create a minimal iframe with a message manager
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozbrowser", "true");
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
let mm = iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
|
||||
|
||||
// Register a test actor in the child process so that we can know if and when
|
||||
// this fake actor is disconnected.
|
||||
mm.loadFrameScript("data:text/javascript,new " + function FrameScriptScope() {
|
||||
const {DebuggerServer} = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
DebuggerServer.init();
|
||||
}
|
||||
|
||||
function TestActor() {dump("instanciate test actor");}
|
||||
TestActor.prototype = {
|
||||
actorPrefix: "test",
|
||||
|
||||
disconnect: function () {
|
||||
sendAsyncMessage("test-actor-disconnected", null);
|
||||
},
|
||||
hello: function () {
|
||||
return {msg:"world"};
|
||||
}
|
||||
};
|
||||
TestActor.prototype.requestTypes = {
|
||||
"hello": TestActor.prototype.hello
|
||||
};
|
||||
DebuggerServer.addTabActor(TestActor, "testActor");
|
||||
}, false);
|
||||
|
||||
// Instantiate a minimal server
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.addBrowserActors();
|
||||
|
||||
function firstClient() {
|
||||
// Fake a first connection to an iframe
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
let conn = transport._serverConnection;
|
||||
let client = new DebuggerClient(transport);
|
||||
DebuggerServer.connectToChild(conn, mm).then(actor => {
|
||||
ok(actor.testActor, "Got the test actor");
|
||||
|
||||
// Ensure sending at least one request to our actor,
|
||||
// otherwise it won't be instanciated, nor be disconnected...
|
||||
client.request({
|
||||
to: actor.testActor,
|
||||
type: "hello",
|
||||
}, function (response) {
|
||||
|
||||
// Then close the client. That should end up cleaning our test actor
|
||||
client.close();
|
||||
|
||||
// Ensure that our test actor got cleaned up;
|
||||
// its disconnect method should be called
|
||||
mm.addMessageListener("test-actor-disconnected", function listener() {
|
||||
mm.removeMessageListener("test-actor-disconnected", listener);
|
||||
ok(true, "Actor is cleaned up");
|
||||
|
||||
secondClient(actor.testActor);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function secondClient(firstActor) {
|
||||
// Then fake a second one, that should spawn a new set of tab actors
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
let conn = transport._serverConnection;
|
||||
let client = new DebuggerClient(transport);
|
||||
DebuggerServer.connectToChild(conn, mm).then(actor => {
|
||||
ok(actor.testActor, "Got a test actor for the second connection");
|
||||
isnot(actor.testActor, firstActor, "We get different actor instances between two connections");
|
||||
|
||||
client.close(cleanup);
|
||||
});
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
DebuggerServer.destroy();
|
||||
iframe.remove();
|
||||
SimpleTest.finish()
|
||||
}
|
||||
|
||||
firstClient();
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче