mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-12 00:50:40 +00:00
Bug 777508 - Notify parent if child processes are terminated through message manager. r=cjones
This commit is contained in:
parent
44fd6174fa
commit
3056ce6dfe
@ -577,6 +577,7 @@ ifneq ($(OS_ARCH),WINNT)
|
||||
ifndef MOZ_JAVA_COMPOSITOR
|
||||
MOCHITEST_FILES_B += \
|
||||
test_messagemanager_assertpermission.html \
|
||||
test_child_process_shutdown_message.html \
|
||||
$(NULL)
|
||||
endif
|
||||
endif
|
||||
|
136
content/base/test/test_child_process_shutdown_message.html
Normal file
136
content/base/test/test_child_process_shutdown_message.html
Normal file
@ -0,0 +1,136 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that processes that are shutdown send a 'process-shutdown'
|
||||
message to their process message manager.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<p id="display">
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.8">
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = SpecialPowers.wrap(Components);
|
||||
|
||||
const APP_URL = "http://example.org";
|
||||
const APP_MANIFEST = "http://example.org/manifest.webapp";
|
||||
const CHILD_PROCESS_SHUTDOWN_MESSAGE = "child-process-shutdown";
|
||||
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
|
||||
/**
|
||||
* Load the example.org app in an <iframe mozbrowser mozapp>
|
||||
*/
|
||||
function loadApp(callback) {
|
||||
let iframe = document.createElement("iframe");
|
||||
iframe.setAttribute("mozapp", APP_MANIFEST);
|
||||
iframe.mozbrowser = true;
|
||||
iframe.src = APP_URL;
|
||||
document.getElementById("content").appendChild(iframe);
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function onloadend() {
|
||||
iframe.removeEventListener("mozbrowserloadend", onloadend);
|
||||
callback(iframe);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the child process for an intentional crash. This is to keep
|
||||
* the leak automation tools happy.
|
||||
*
|
||||
* This also allows us to acquire the process message manaager that
|
||||
* corresponds to the process by sending a message to a frame script
|
||||
* in the content process and having it reply to us via the child
|
||||
* process message manager.
|
||||
*/
|
||||
function prepareProcess(frameMM, callback) {
|
||||
let frameScript = 'data:,\
|
||||
privateNoteIntentionalCrash();\
|
||||
var cpmm = Components.classes["@mozilla.org/childprocessmessagemanager;1"]\
|
||||
.getService(Components.interfaces.nsISyncMessageSender);\
|
||||
addMessageListener("TestChild:Ohai", function receiveMessage(msg) {\
|
||||
cpmm.sendAsyncMessage("TestChild:Ohai");\
|
||||
});';
|
||||
frameMM.loadFrameScript(frameScript, false);
|
||||
frameMM.sendAsyncMessage("TestChild:Ohai");
|
||||
ppmm.addMessageListener("TestChild:Ohai", function receiveMessage(msg) {
|
||||
ppmm.removeMessageListener("TestChild:Ohai", receiveMessage);
|
||||
msg = SpecialPowers.wrap(msg);
|
||||
callback(msg.target);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects an OOP frame's process to shut down and report three
|
||||
* events/messages: an error event on the browser element, and a
|
||||
* 'child-process-shutdown' message on both the frame and process
|
||||
* message managers.
|
||||
*/
|
||||
function expectFrameProcessShutdown(iframe, frameMM, processMM, callback) {
|
||||
let msgCount = 0;
|
||||
function countMessage() {
|
||||
msgCount += 1;
|
||||
if (msgCount == 3) {
|
||||
ok(true, "Observed all three expected events.");
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
iframe.addEventListener("mozbrowsererror", function onerror(event) {
|
||||
iframe.removeEventListener("mozbrowsererror", onerror);
|
||||
is(event.detail.type, "fatal", "Observed expected event.");
|
||||
countMessage();
|
||||
});
|
||||
|
||||
processMM.addMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, function receiveMessage() {
|
||||
processMM.removeMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, receiveMessage);
|
||||
ok(true, "Received 'child-process-shutdown' message from process message manager.");
|
||||
countMessage();
|
||||
});
|
||||
|
||||
frameMM.addMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, function receiveMessage() {
|
||||
frameMM.removeMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, receiveMessage);
|
||||
ok(true, "Received 'child-process-shutdown' message from frame message manager.");
|
||||
countMessage();
|
||||
});
|
||||
}
|
||||
|
||||
function runTests(callback) {
|
||||
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
|
||||
SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", true);
|
||||
SpecialPowers.addPermission("browser", true, window.document);
|
||||
|
||||
function tearDown() {
|
||||
SpecialPowers.clearUserPref("dom.mozBrowserFramesEnabled");
|
||||
SpecialPowers.clearUserPref("dom.ipc.browser_frames.oop_by_default");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
loadApp(function (iframe) {
|
||||
// We want to make sure we get notified on both the frame and
|
||||
// process message managers.
|
||||
let frameMM = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
prepareProcess(frameMM, function (processMM) {
|
||||
// Let's kill the content process by asking for a permission
|
||||
// that it doesn't have.
|
||||
ok(!processMM.assertPermission("frobnaz"),
|
||||
"Content child should not have this permission");
|
||||
expectFrameProcessShutdown(iframe, frameMM, processMM, function () {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
tearDown();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -19,6 +19,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = SpecialPowers.wrap
|
||||
|
||||
const APP_URL = "http://example.org";
|
||||
const APP_MANIFEST = "http://example.org/manifest.webapp";
|
||||
const CHILD_PROCESS_SHUTDOWN_MESSAGE = "child-process-shutdown";
|
||||
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
@ -81,6 +82,41 @@ function prepareProcess(frameMM, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Expects an OOP frame's process to shut down and report three
|
||||
* events/messages: an error event on the browser element, and a
|
||||
* 'child-process-shutdown' message on both the frame and process
|
||||
* message managers.
|
||||
*/
|
||||
function expectFrameProcessShutdown(iframe, frameMM, processMM, callback) {
|
||||
let msgCount = 0;
|
||||
function countMessage() {
|
||||
msgCount += 1;
|
||||
if (msgCount == 3) {
|
||||
ok(true, "Observed all three expected events.");
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
iframe.addEventListener("mozbrowsererror", function onerror(event) {
|
||||
iframe.removeEventListener("mozbrowsererror", onerror);
|
||||
is(event.detail.type, "fatal", "Observed expected event.");
|
||||
countMessage();
|
||||
});
|
||||
|
||||
processMM.addMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, function receiveMessage() {
|
||||
processMM.removeMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, receiveMessage);
|
||||
ok(true, "Received 'child-process-shutdown' message from process message manager.");
|
||||
countMessage();
|
||||
});
|
||||
|
||||
frameMM.addMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, function receiveMessage() {
|
||||
frameMM.removeMessageListener(CHILD_PROCESS_SHUTDOWN_MESSAGE, receiveMessage);
|
||||
ok(true, "Received 'child-process-shutdown' message from frame message manager.");
|
||||
countMessage();
|
||||
});
|
||||
}
|
||||
|
||||
function testSameProcess() {
|
||||
// Assert permissions on the in-process child process message manager.
|
||||
// It always has all permissions, including ones that were never
|
||||
@ -106,13 +142,7 @@ function testFrameMessageManager() {
|
||||
"Frame mm has assigned permission.");
|
||||
ok(!frameMM.assertPermission("frobnaz"),
|
||||
"Frame mm doesn't have non-existing permission.");
|
||||
|
||||
// The last permission check will result in the content process
|
||||
// being killed.
|
||||
iframe.addEventListener("mozbrowsererror", function onerror(event) {
|
||||
iframe.removeEventListener("mozbrowsererror", onerror);
|
||||
is(event.detail.type, "fatal", "Observed expected event.");
|
||||
|
||||
expectFrameProcessShutdown(iframe, frameMM, processMM, function () {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
runNextTest();
|
||||
});
|
||||
@ -130,13 +160,7 @@ function testChildProcessMessageManager() {
|
||||
"Process mm has assigned permission.");
|
||||
ok(!processMM.assertPermission("frobnaz"),
|
||||
"Process mm doesn't have non-existing permission.");
|
||||
|
||||
// The last permission check will result in the content process
|
||||
// being killed.
|
||||
iframe.addEventListener("mozbrowsererror", function onerror(event) {
|
||||
iframe.removeEventListener("mozbrowsererror", onerror);
|
||||
is(event.detail.type, "fatal", "Observed expected event.");
|
||||
|
||||
expectFrameProcessShutdown(iframe, frameMM, processMM, function () {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
runNextTest();
|
||||
});
|
||||
|
@ -573,6 +573,12 @@ struct DelayedDeleteContentParentTask : public nsRunnable
|
||||
void
|
||||
ContentParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
nsRefPtr<nsFrameMessageManager> ppm = mMessageManager;
|
||||
if (ppm) {
|
||||
ppm->ReceiveMessage(static_cast<nsIContentFrameMessageManager*>(ppm.get()),
|
||||
CHILD_PROCESS_SHUTDOWN_MESSAGE, false,
|
||||
nullptr, nullptr, nullptr);
|
||||
}
|
||||
nsCOMPtr<nsIThreadObserver>
|
||||
kungFuDeathGrip(static_cast<nsIThreadObserver*>(this));
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
#define CHILD_PROCESS_SHUTDOWN_MESSAGE NS_LITERAL_STRING("child-process-shutdown")
|
||||
|
||||
class mozIApplication;
|
||||
class nsIDOMBlob;
|
||||
|
||||
|
@ -132,6 +132,7 @@ TabParent::ActorDestroy(ActorDestroyReason why)
|
||||
}
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
if (frameLoader) {
|
||||
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
|
||||
frameLoader->DestroyChild();
|
||||
|
||||
if (why == AbnormalShutdown) {
|
||||
|
Loading…
Reference in New Issue
Block a user