mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 23:02:20 +00:00
80f0c61cf5
Differential Revision: https://phabricator.services.mozilla.com/D210309
181 lines
5.9 KiB
C++
181 lines
5.9 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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/. */
|
|
|
|
#include "CrashReporterHost.h"
|
|
#include "mozilla/dom/Promise.h"
|
|
#include "mozilla/Sprintf.h"
|
|
#include "mozilla/SyncRunnable.h"
|
|
#include "mozilla/Telemetry.h"
|
|
#include "nsServiceManagerUtils.h"
|
|
#include "nsICrashService.h"
|
|
#include "nsXULAppAPI.h"
|
|
#include "nsIFile.h"
|
|
|
|
namespace mozilla {
|
|
namespace ipc {
|
|
|
|
CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
|
|
CrashReporter::ThreadId aThreadId)
|
|
: mProcessType(aProcessType),
|
|
mThreadId(aThreadId),
|
|
mStartTime(::time(nullptr)),
|
|
mFinalized(false) {}
|
|
|
|
bool CrashReporterHost::GenerateCrashReport(base::ProcessId aPid) {
|
|
if (!TakeCrashedChildMinidump(aPid)) {
|
|
return false;
|
|
}
|
|
|
|
FinalizeCrashReport();
|
|
RecordCrash(mProcessType, nsICrashService::CRASH_TYPE_CRASH, mDumpID);
|
|
return true;
|
|
}
|
|
|
|
RefPtr<nsIFile> CrashReporterHost::TakeCrashedChildMinidump(
|
|
base::ProcessId aPid) {
|
|
CrashReporter::AnnotationTable annotations;
|
|
MOZ_ASSERT(!HasMinidump());
|
|
|
|
RefPtr<nsIFile> crashDump;
|
|
if (!CrashReporter::TakeMinidumpForChild(aPid, getter_AddRefs(crashDump),
|
|
annotations)) {
|
|
return nullptr;
|
|
}
|
|
if (!AdoptMinidump(crashDump, annotations)) {
|
|
return nullptr;
|
|
}
|
|
return crashDump;
|
|
}
|
|
|
|
bool CrashReporterHost::AdoptMinidump(nsIFile* aFile,
|
|
const AnnotationTable& aAnnotations) {
|
|
if (!CrashReporter::GetIDFromMinidump(aFile, mDumpID)) {
|
|
return false;
|
|
}
|
|
|
|
MergeCrashAnnotations(mExtraAnnotations, aAnnotations);
|
|
return true;
|
|
}
|
|
|
|
void CrashReporterHost::FinalizeCrashReport() {
|
|
MOZ_ASSERT(!mFinalized);
|
|
MOZ_ASSERT(HasMinidump());
|
|
|
|
mExtraAnnotations[CrashReporter::Annotation::ProcessType] =
|
|
XRE_ChildProcessTypeToAnnotation(mProcessType);
|
|
|
|
char startTime[32];
|
|
SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
|
|
mExtraAnnotations[CrashReporter::Annotation::StartupTime] =
|
|
nsDependentCString(startTime);
|
|
|
|
CrashReporter::WriteExtraFile(mDumpID, mExtraAnnotations);
|
|
mFinalized = true;
|
|
}
|
|
|
|
void CrashReporterHost::DeleteCrashReport() {
|
|
if (mFinalized && HasMinidump()) {
|
|
CrashReporter::DeleteMinidumpFilesForID(mDumpID, Some(u"browser"_ns));
|
|
}
|
|
}
|
|
|
|
/* static */
|
|
void CrashReporterHost::RecordCrash(GeckoProcessType aProcessType,
|
|
int32_t aCrashType,
|
|
const nsString& aChildDumpID) {
|
|
if (!NS_IsMainThread()) {
|
|
RefPtr<Runnable> runnable = NS_NewRunnableFunction(
|
|
"ipc::CrashReporterHost::RecordCrash", [&]() -> void {
|
|
CrashReporterHost::RecordCrash(aProcessType, aCrashType,
|
|
aChildDumpID);
|
|
});
|
|
RefPtr<nsIThread> mainThread = do_GetMainThread();
|
|
SyncRunnable::DispatchToThread(mainThread, runnable);
|
|
return;
|
|
}
|
|
|
|
RecordCrashWithTelemetry(aProcessType, aCrashType);
|
|
NotifyCrashService(aProcessType, aCrashType, aChildDumpID);
|
|
}
|
|
|
|
/* static */
|
|
void CrashReporterHost::RecordCrashWithTelemetry(GeckoProcessType aProcessType,
|
|
int32_t aCrashType) {
|
|
nsCString key;
|
|
|
|
switch (aProcessType) {
|
|
#define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
|
|
process_bin_type, procinfo_typename, \
|
|
webidl_typename, allcaps_name) \
|
|
case GeckoProcessType_##enum_name: \
|
|
key.AssignLiteral(string_name); \
|
|
break;
|
|
#include "mozilla/GeckoProcessTypes.h"
|
|
#undef GECKO_PROCESS_TYPE
|
|
// We can't really hit this, thanks to the above switch, but having it
|
|
// here will placate the compiler.
|
|
default:
|
|
MOZ_ASSERT_UNREACHABLE("unknown process type");
|
|
}
|
|
|
|
Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, key, 1);
|
|
}
|
|
|
|
/* static */
|
|
void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
|
|
int32_t aCrashType,
|
|
const nsString& aChildDumpID) {
|
|
MOZ_ASSERT(!aChildDumpID.IsEmpty());
|
|
|
|
nsCOMPtr<nsICrashService> crashService =
|
|
do_GetService("@mozilla.org/crashservice;1");
|
|
if (!crashService) {
|
|
return;
|
|
}
|
|
|
|
int32_t processType;
|
|
|
|
switch (aProcessType) {
|
|
case GeckoProcessType_IPDLUnitTest:
|
|
case GeckoProcessType_Default:
|
|
NS_ERROR("unknown process type");
|
|
return;
|
|
default:
|
|
processType = (int)aProcessType;
|
|
break;
|
|
}
|
|
|
|
RefPtr<dom::Promise> promise;
|
|
crashService->AddCrash(processType, aCrashType, aChildDumpID,
|
|
getter_AddRefs(promise));
|
|
}
|
|
|
|
void CrashReporterHost::AddAnnotationBool(CrashReporter::Annotation aKey,
|
|
bool aValue) {
|
|
MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::Boolean,
|
|
"Wrong annotation type");
|
|
mExtraAnnotations[aKey] = aValue ? "1"_ns : "0"_ns;
|
|
}
|
|
|
|
void CrashReporterHost::AddAnnotationU32(CrashReporter::Annotation aKey,
|
|
uint32_t aValue) {
|
|
MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::U32,
|
|
"Wrong annotation type");
|
|
nsAutoCString valueString;
|
|
valueString.AppendInt(aValue);
|
|
mExtraAnnotations[aKey] = valueString;
|
|
}
|
|
|
|
void CrashReporterHost::AddAnnotationNSCString(CrashReporter::Annotation aKey,
|
|
const nsACString& aValue) {
|
|
MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::String,
|
|
"Wrong annotation type");
|
|
mExtraAnnotations[aKey] = aValue;
|
|
}
|
|
|
|
} // namespace ipc
|
|
} // namespace mozilla
|