bug 484033 - extend nsICrashReporter to allow crashreporter to be used without going through XRE_Main. r=bsmedberg

This commit is contained in:
Ted Mielczarek 2009-04-02 11:41:12 -04:00
parent df2a416e74
commit a8a9796d5c
6 changed files with 236 additions and 13 deletions

View File

@ -82,6 +82,7 @@ namespace CrashReporter {
#ifdef XP_WIN32
typedef wchar_t XP_CHAR;
#define CONVERT_UTF16_TO_XP_CHAR(x) x
#define CONVERT_XP_CHAR_TO_UTF16(x) x
#define XP_STRLEN(x) wcslen(x)
#define CRASH_REPORTER_FILENAME "crashreporter.exe"
#define PATH_SEPARATOR "\\"
@ -98,6 +99,7 @@ typedef wchar_t XP_CHAR;
#else
typedef char XP_CHAR;
#define CONVERT_UTF16_TO_XP_CHAR(x) NS_ConvertUTF16toUTF8(x)
#define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x)
#define XP_STRLEN(x) strlen(x)
#define CRASH_REPORTER_FILENAME "crashreporter"
#define PATH_SEPARATOR "/"
@ -314,7 +316,7 @@ bool MinidumpCallback(const XP_CHAR* dump_path,
}
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
const char* aServerURL)
bool force/*=false*/)
{
nsresult rv;
@ -322,7 +324,7 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
return NS_ERROR_ALREADY_INITIALIZED;
const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
if (envvar && *envvar)
if (envvar && *envvar && !force)
return NS_OK;
// this environment variable prevents us from launching
@ -418,11 +420,6 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
if (!gExceptionHandler)
return NS_ERROR_OUT_OF_MEMORY;
// store server URL with the API data
if (aServerURL)
AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
nsDependentCString(aServerURL));
// store application start time
char timeString[32];
XP_TTOA(time(NULL), timeString, 10);
@ -439,6 +436,20 @@ nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
return NS_OK;
}
bool GetEnabled()
{
return gExceptionHandler != nsnull;
}
bool GetMinidumpPath(nsAString& aPath)
{
if (!gExceptionHandler)
return false;
aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str());
return true;
}
nsresult SetMinidumpPath(const nsAString& aPath)
{
if (!gExceptionHandler)
@ -760,7 +771,7 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data)
bool GetAnnotation(const nsACString& key, nsACString& data)
{
if (!gExceptionHandler)
return NS_ERROR_NOT_INITIALIZED;
return false;
nsCAutoString entry;
if (!crashReporterAPIData_Hash->Get(key, &entry))
@ -770,6 +781,22 @@ bool GetAnnotation(const nsACString& key, nsACString& data)
return true;
}
bool GetServerURL(nsACString& aServerURL)
{
if (!gExceptionHandler)
return false;
return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL);
}
nsresult SetServerURL(const nsACString& aServerURL)
{
// store server URL with the API data
// the client knows to handle this specially
return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
aServerURL);
}
nsresult
SetRestartArgs(int argc, char** argv)
{

View File

@ -50,10 +50,13 @@
#endif
namespace CrashReporter {
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
const char* aServerURL);
nsresult SetMinidumpPath(const nsAString& aPath);
nsresult SetExceptionHandler(nsILocalFile* aXREDirectory, bool force=false);
nsresult UnsetExceptionHandler();
bool GetEnabled();
bool GetServerURL(nsACString& aServerURL);
nsresult SetServerURL(const nsACString& aServerURL);
bool GetMinidumpPath(nsAString& aPath);
nsresult SetMinidumpPath(const nsAString& aPath);
nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data);
nsresult AppendAppNotesToCrashReport(const nsACString& data);
nsresult SetRestartArgs(int argc, char** argv);

View File

@ -42,6 +42,9 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = crashreporter
XPCSHELL_TESTS = unit
ifndef MOZ_ENABLE_LIBXUL
PROGRAM = TestCrashReporterAPI$(BIN_SUFFIX)

View File

@ -0,0 +1,55 @@
function run_test()
{
if (!("@mozilla.org/toolkit/crash-reporter;1" in Components.classes)) {
do_check_true(true, "Can't test this in a non-libxul build");
return;
}
var cr = Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
.getService(Components.interfaces.nsICrashReporter);
do_check_neq(cr, null);
// check that we can enable the crashreporter
do_check_false(cr.enabled);
cr.enabled = true;
do_check_true(cr.enabled);
// ensure that double-enabling doesn't error
cr.enabled = true;
// check setting/getting serverURL
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
// try it with two different URLs, just for kicks
var testspecs = ["http://example.com/submit",
"https://example.org/anothersubmit"];
for (var i=0; i<testspecs.length; i++) {
var u = ios.newURI(testspecs[i], null, null);
cr.serverURL = u;
do_check_eq(cr.serverURL.spec, testspecs[i]);
}
// should not allow setting non-http/https URLs
try {
u = ios.newURI("ftp://example.com/submit", null, null);
cr.serverURL = u;
do_throw("Setting serverURL to a non-http URL should have thrown!");
}
catch(ex) {
do_check_eq(ex.result, Components.results.NS_ERROR_INVALID_ARG);
}
// check getting/setting minidumpPath
// it should be $TEMP initially, but I'm not sure if we can exactly test that
// this will at least test that it doesn't throw
do_check_neq(cr.minidumpPath.path, "");
var cwd = do_get_cwd();
cr.minidumpPath = cwd;
do_check_eq(cr.minidumpPath.path, cwd.path);
// check that we can disable the crashreporter
cr.enabled = false;
do_check_false(cr.enabled);
// ensure that double-disabling doesn't error
cr.enabled = false;
}

View File

@ -788,6 +788,114 @@ nsXULAppInfo::GetUserCanElevate(PRBool *aUserCanElevate)
#endif
#ifdef MOZ_CRASHREPORTER
NS_IMETHODIMP
nsXULAppInfo::GetEnabled(PRBool *aEnabled)
{
*aEnabled = CrashReporter::GetEnabled();
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetEnabled(PRBool aEnabled)
{
if (aEnabled) {
if (CrashReporter::GetEnabled())
// no point in erroring for double-enabling
return NS_OK;
nsCOMPtr<nsILocalFile> xreDirectory;
if (gAppData) {
xreDirectory = gAppData->xreDirectory;
}
else {
// We didn't get started through XRE_Main, probably
nsCOMPtr<nsIFile> greDir;
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(greDir));
if (!greDir)
return NS_ERROR_FAILURE;
xreDirectory = do_QueryInterface(greDir);
if (!xreDirectory)
return NS_ERROR_FAILURE;
}
return CrashReporter::SetExceptionHandler(xreDirectory, true);
}
else {
if (!CrashReporter::GetEnabled())
// no point in erroring for double-disabling
return NS_OK;
return CrashReporter::UnsetExceptionHandler();
}
}
NS_IMETHODIMP
nsXULAppInfo::GetServerURL(nsIURL** aServerURL)
{
if (!CrashReporter::GetEnabled())
return NS_ERROR_NOT_INITIALIZED;
nsCAutoString data;
if (!CrashReporter::GetServerURL(data)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), data);
if (!uri)
return NS_ERROR_FAILURE;
nsCOMPtr<nsIURL> url;
url = do_QueryInterface(uri);
NS_ADDREF(*aServerURL = url);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetServerURL(nsIURL* aServerURL)
{
PRBool schemeOk;
// only allow https or http URLs
nsresult rv = aServerURL->SchemeIs("https", &schemeOk);
NS_ENSURE_SUCCESS(rv, rv);
if (!schemeOk) {
rv = aServerURL->SchemeIs("http", &schemeOk);
NS_ENSURE_SUCCESS(rv, rv);
if (!schemeOk)
return NS_ERROR_INVALID_ARG;
}
nsCAutoString spec;
rv = aServerURL->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
return CrashReporter::SetServerURL(spec);
}
NS_IMETHODIMP
nsXULAppInfo::GetMinidumpPath(nsILocalFile** aMinidumpPath)
{
if (!CrashReporter::GetEnabled())
return NS_ERROR_NOT_INITIALIZED;
nsAutoString path;
if (!CrashReporter::GetMinidumpPath(path))
return NS_ERROR_FAILURE;
nsresult rv = NS_NewLocalFile(path, PR_FALSE, aMinidumpPath);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsXULAppInfo::SetMinidumpPath(nsILocalFile* aMinidumpPath)
{
nsAutoString path;
nsresult rv = aMinidumpPath->GetPath(path);
NS_ENSURE_SUCCESS(rv, rv);
return CrashReporter::SetMinidumpPath(path);
}
NS_IMETHODIMP
nsXULAppInfo::AnnotateCrashReport(const nsACString& key,
const nsACString& data)
@ -2641,8 +2749,8 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
if ((appData.flags & NS_XRE_ENABLE_CRASH_REPORTER) &&
NS_SUCCEEDED(
CrashReporter::SetExceptionHandler(appData.xreDirectory,
appData.crashReporterURL))) {
CrashReporter::SetExceptionHandler(appData.xreDirectory))) {
CrashReporter::SetServerURL(nsDependentCString(appData.crashReporterURL));
// pass some basic info from the app data
if (appData.vendor)
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"),

View File

@ -37,6 +37,9 @@
#include "nsISupports.idl"
interface nsILocalFile;
interface nsIURL;
/**
* Provides access to crash reporting functionality.
* @status UNSTABLE - This interface is not frozen and will probably change in
@ -46,6 +49,30 @@
[scriptable, uuid(D9A0F5B2-A7DF-4AEB-9775-21B9E01B4C59)]
interface nsICrashReporter : nsISupports
{
/**
* Enable or disable the crashreporter at runtime.
*/
attribute boolean enabled;
/**
* Get or set the URL to which crash reports will be submitted.
* Only https and http URLs are allowed, as the submission is handled
* by OS-native networking libraries.
*
* @throw NS_ERROR_NOT_INITIALIZED if crash reporting is not initialized
* @throw NS_ERROR_INVALID_ARG on set if a non-http(s) URL is assigned
* @throw NS_ERROR_FAILURE on get if no URL is set
*/
attribute nsIURL serverURL;
/**
* Get or set the path on the local system to which minidumps will be
* written when a crash happens.
*
* @throw NS_ERROR_NOT_INITIALIZED if crash reporting is not initialized
*/
attribute nsILocalFile minidumpPath;
/**
* Add some extra data to be submitted with a crash report.
* @param key