mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 602891 part B - Backend support for jetpack-process crashes and crash recovery, r=cjones
On crash, an event will be submitted to the parent with the name "core:process-error" with a context object. If crash reporting is enabled and a crash report is available, the context object will have a .dumpID property which can be used to submit the crash report. --HG-- extra : rebase_source : d089bb451271999ae3861a83f2b21ba8ec9e0122
This commit is contained in:
parent
e5050e3722
commit
dd3cf56a97
@ -42,6 +42,7 @@
|
||||
|
||||
#include "mozilla/jetpack/JetpackChild.h"
|
||||
#include "mozilla/jetpack/Handle.h"
|
||||
#include "mozilla/IntentionalCrash.h"
|
||||
|
||||
#include "jsarray.h"
|
||||
|
||||
@ -75,6 +76,8 @@ JetpackChild::sImplMethods[] = {
|
||||
#ifdef JS_GC_ZEAL
|
||||
JS_FN("gczeal", GCZeal, 1, IMPL_METHOD_FLAGS),
|
||||
#endif
|
||||
JS_FN("_noteIntentionalCrash", NoteIntentionalCrash, 0,
|
||||
IMPL_METHOD_FLAGS),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
@ -563,5 +566,12 @@ JetpackChild::GCZeal(JSContext* cx, uintN argc, jsval *vp)
|
||||
}
|
||||
#endif
|
||||
|
||||
JSBool
|
||||
JetpackChild::NoteIntentionalCrash(JSContext* cx, uintN argc, jsval *vp)
|
||||
{
|
||||
mozilla::NoteIntentionalCrash("jetpack");
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
} // namespace jetpack
|
||||
} // namespace mozilla
|
||||
|
@ -93,6 +93,7 @@ private:
|
||||
#ifdef JS_GC_ZEAL
|
||||
static JSBool GCZeal(JSContext* cx, uintN argc, jsval *vp);
|
||||
#endif
|
||||
static JSBool NoteIntentionalCrash(JSContext* cx, uintN argc, jsval *vp);
|
||||
|
||||
static void ReportError(JSContext* cx, const char* message,
|
||||
JSErrorReport* report);
|
||||
|
@ -45,12 +45,17 @@
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
#include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace jetpack {
|
||||
|
||||
JetpackParent::JetpackParent(JSContext* cx)
|
||||
: mSubprocess(new JetpackProcessParent())
|
||||
, mContext(cx)
|
||||
, mTaskFactory(this)
|
||||
{
|
||||
mSubprocess->Launch();
|
||||
Open(mSubprocess->GetChannel(),
|
||||
@ -152,6 +157,7 @@ public:
|
||||
AutoCXPusher(JSContext* cx)
|
||||
: mCXStack(do_GetService("@mozilla.org/js/xpc/ContextStack;1"))
|
||||
{
|
||||
NS_ASSERTION(mCXStack, "No JS context stack?");
|
||||
if (mCXStack)
|
||||
mCXStack->Push(cx);
|
||||
}
|
||||
@ -166,6 +172,39 @@ private:
|
||||
JSContext* mCX;
|
||||
};
|
||||
|
||||
void
|
||||
JetpackParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
switch (why) {
|
||||
case AbnormalShutdown: {
|
||||
nsAutoString dumpID;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
nsCOMPtr<nsILocalFile> crashDump;
|
||||
TakeMinidump(getter_AddRefs(crashDump)) &&
|
||||
CrashReporter::GetIDFromMinidump(crashDump, dumpID);
|
||||
#endif
|
||||
|
||||
MessageLoop::current()->
|
||||
PostTask(FROM_HERE,
|
||||
mTaskFactory.NewRunnableMethod(
|
||||
&JetpackParent::DispatchFailureMessage,
|
||||
dumpID));
|
||||
break;
|
||||
}
|
||||
|
||||
case NormalShutdown:
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_ERROR("Unexpected actordestroy reason for toplevel actor.");
|
||||
}
|
||||
|
||||
XRE_GetIOMessageLoop()
|
||||
->PostTask(FROM_HERE, new DeleteTask<JetpackProcessParent>(mSubprocess));
|
||||
mSubprocess = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
JetpackParent::RecvSendMessage(const nsString& messageName,
|
||||
const InfallibleTArray<Variant>& data)
|
||||
@ -222,14 +261,10 @@ JetpackParent::CreateHandle(nsIVariant** aResult)
|
||||
NS_IMETHODIMP
|
||||
JetpackParent::Destroy()
|
||||
{
|
||||
if (!mSubprocess)
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
Close();
|
||||
XRE_GetIOMessageLoop()
|
||||
->PostTask(FROM_HERE, new DeleteTask<JetpackProcessParent>(mSubprocess));
|
||||
mSubprocess = NULL;
|
||||
if (mSubprocess)
|
||||
Close();
|
||||
|
||||
NS_ASSERTION(!mSubprocess, "ActorDestroy should have been called.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -256,5 +291,20 @@ JetpackParent::OnChannelConnected(int32 pid)
|
||||
SetOtherProcess(handle);
|
||||
}
|
||||
|
||||
void
|
||||
JetpackParent::DispatchFailureMessage(const nsString& aDumpID)
|
||||
{
|
||||
KeyValue kv(NS_LITERAL_STRING("dumpID"), PrimVariant(aDumpID));
|
||||
InfallibleTArray<KeyValue> keyvalues;
|
||||
keyvalues.AppendElement(kv);
|
||||
|
||||
CompVariant object(keyvalues);
|
||||
|
||||
InfallibleTArray<Variant> arguments;
|
||||
arguments.AppendElement(object);
|
||||
|
||||
RecvSendMessage(NS_LITERAL_STRING("core:process-error"), arguments);
|
||||
}
|
||||
|
||||
} // namespace jetpack
|
||||
} // namespace mozilla
|
||||
|
@ -68,6 +68,8 @@ public:
|
||||
void OnChannelConnected(int32 pid);
|
||||
|
||||
protected:
|
||||
NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why);
|
||||
|
||||
NS_OVERRIDE virtual bool RecvSendMessage(const nsString& messageName,
|
||||
const InfallibleTArray<Variant>& data);
|
||||
NS_OVERRIDE virtual bool AnswerCallMessage(const nsString& messageName,
|
||||
@ -80,6 +82,9 @@ protected:
|
||||
private:
|
||||
JetpackProcessParent* mSubprocess;
|
||||
JSContext* mContext;
|
||||
ScopedRunnableMethodFactory<JetpackParent> mTaskFactory;
|
||||
|
||||
void DispatchFailureMessage(const nsString& aDumpID);
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(JetpackParent);
|
||||
};
|
||||
|
@ -49,3 +49,12 @@ XPCSHELL_TESTS = unit
|
||||
|
||||
include $(topsrcdir)/config/config.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT)) # Disabled for bug 599475
|
||||
MOCHICHROME_FILES = \
|
||||
test_jetpack_crash.xul \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(MOCHICHROME_FILES)
|
||||
$(INSTALL) $^ $(DEPTH)/_tests/testing/mochitest/chrome/$(relativesrcdir)
|
||||
endif
|
||||
|
84
js/jetpack/tests/test_jetpack_crash.xul
Normal file
84
js/jetpack/tests/test_jetpack_crash.xul
Normal file
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css" ?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css" ?>
|
||||
|
||||
<window title="Jetpack Crash Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
|
||||
<description id="remoteScript">
|
||||
<![CDATA[
|
||||
registerReceiver("testCTypes", function(name, libfile) {
|
||||
var library = ctypes.open(libfile);
|
||||
var zero = new ctypes.intptr_t(8);
|
||||
_noteIntentionalCrash();
|
||||
var badptr = ctypes.cast(zero, ctypes.PointerType(ctypes.int32_t));
|
||||
sendMessage("testCTypes:response", badptr.contents); // should crash here!
|
||||
});
|
||||
]]>
|
||||
</description>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
Components.utils.import("resource://gre/modules/ctypes.jsm");
|
||||
const libURL = "chrome://mochitests/content/chrome/libraries/" +
|
||||
ctypes.libraryName("jsctypes-test");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var jp = Components.classes["@mozilla.org/jetpack/service;1"].
|
||||
getService(Components.interfaces.nsIJetpackService).
|
||||
createJetpack();
|
||||
|
||||
jp.registerReceiver("core:exception", function(msgName, e) {
|
||||
ok(false, "Received exception from remote code: " + uneval(e));
|
||||
});
|
||||
|
||||
jp.registerReceiver("testCTypes:response", function(msgName, v) {
|
||||
ok(false, "Should not have received testCTypes response!");
|
||||
jp.destroy();
|
||||
jp = null;
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
jp.registerReceiver("core:process-error", function(msgName, e) {
|
||||
ok(true, "Received process-error notification.");
|
||||
|
||||
if ('nsICrashReporter' in Components.interfaces)
|
||||
ok(e.dumpID, "Process error has a dumpID");
|
||||
|
||||
jp.destroy();
|
||||
jp = null;
|
||||
|
||||
SimpleTest.executeSoon(SimpleTest.finish);
|
||||
});
|
||||
|
||||
var remoteScript = document.getElementById('remoteScript').textContent;
|
||||
jp.evalScript(remoteScript);
|
||||
|
||||
var downloadObserver = {
|
||||
onDownloadComplete: function(downloader, request, cx, status, file) {
|
||||
Components.utils.reportError("download status: " + status);
|
||||
try {
|
||||
file.permission = 0700;
|
||||
}
|
||||
catch (e) {
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
jp.sendMessage('testCTypes', file.path);
|
||||
}
|
||||
};
|
||||
var downloader = Components.classes["@mozilla.org/network/downloader;1"].
|
||||
createInstance(Components.interfaces.nsIDownloader);
|
||||
downloader.init(downloadObserver, null);
|
||||
var channel = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService).
|
||||
newChannel(libURL, null, null);
|
||||
channel.asyncOpen(downloader, null);
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
@ -84,6 +84,7 @@ libs:: unit/test_jsctypes.js.in
|
||||
$(PYTHON) $(MOZILLA_DIR)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
|
||||
$^ > $(xpctestdir)/test_jsctypes.js
|
||||
$(TEST_INSTALLER) $(SHARED_LIBRARY) $(xpctestdir)
|
||||
$(TEST_INSTALLER) $(SHARED_LIBRARY) $(DEPTH)/_tests/testing/mochitest/chrome/libraries
|
||||
$(TEST_INSTALLER) $(xpctestdir)/test_jsctypes.js $(chrometestdir)
|
||||
$(TEST_INSTALLER) $(xpctestdir)/$(SHARED_LIBRARY) $(chrometestdir)
|
||||
$(RM) $(xpctestdir)/test_jsctypes.js.in
|
||||
|
Loading…
Reference in New Issue
Block a user