gecko-dev/ipc/glue/CrashReporterHost.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

181 строка
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) {
Bug 1547698 - Refactor the code that writes the .extra file for a content process crash or hang r=froydnj Upon a content process crash or hang crash annotations were incrementally written into the .extra file starting with the exception handler callback and then in a number of different places before the file was ready for submission. This had a number of downsides: since the annotations were directly added to the file it was impossible to tell which ones were already written at a certain point in time, additionally some were written twice or even thrice. The code doing the writing would also behave differently depending on the contents of the file, the parameters passed to it and the contents of global variables. This change overhauls the whole process by keeping the annotations into a temporary per-crash annotation table which is filled with all the required annotations before being written out in a single pass when they are ready. The annotations are gathered from the main process annotation table, the per-process one (held by the CrashReporterHost) and exception-time specific ones. The resulting annotations are slightly different than before the patch: first of all there are no more duplicate entries in the .extra file and secondly all content/plugin process hangs annotations are properly filtered, before annotations that were main process-only would leak into them. Differential Revision: https://phabricator.services.mozilla.com/D31069 --HG-- extra : moz-landing-system : lando
2019-05-18 19:19:55 +03:00
CrashReporter::AnnotationTable annotations;
MOZ_ASSERT(!HasMinidump());
RefPtr<nsIFile> crashDump;
if (!CrashReporter::TakeMinidumpForChild(aPid, getter_AddRefs(crashDump),
annotations)) {
return nullptr;
}
Bug 1547698 - Refactor the code that writes the .extra file for a content process crash or hang r=froydnj Upon a content process crash or hang crash annotations were incrementally written into the .extra file starting with the exception handler callback and then in a number of different places before the file was ready for submission. This had a number of downsides: since the annotations were directly added to the file it was impossible to tell which ones were already written at a certain point in time, additionally some were written twice or even thrice. The code doing the writing would also behave differently depending on the contents of the file, the parameters passed to it and the contents of global variables. This change overhauls the whole process by keeping the annotations into a temporary per-crash annotation table which is filled with all the required annotations before being written out in a single pass when they are ready. The annotations are gathered from the main process annotation table, the per-process one (held by the CrashReporterHost) and exception-time specific ones. The resulting annotations are slightly different than before the patch: first of all there are no more duplicate entries in the .extra file and secondly all content/plugin process hangs annotations are properly filtered, before annotations that were main process-only would leak into them. Differential Revision: https://phabricator.services.mozilla.com/D31069 --HG-- extra : moz-landing-system : lando
2019-05-18 19:19:55 +03:00
if (!AdoptMinidump(crashDump, annotations)) {
return nullptr;
}
Bug 1547698 - Refactor the code that writes the .extra file for a content process crash or hang r=froydnj Upon a content process crash or hang crash annotations were incrementally written into the .extra file starting with the exception handler callback and then in a number of different places before the file was ready for submission. This had a number of downsides: since the annotations were directly added to the file it was impossible to tell which ones were already written at a certain point in time, additionally some were written twice or even thrice. The code doing the writing would also behave differently depending on the contents of the file, the parameters passed to it and the contents of global variables. This change overhauls the whole process by keeping the annotations into a temporary per-crash annotation table which is filled with all the required annotations before being written out in a single pass when they are ready. The annotations are gathered from the main process annotation table, the per-process one (held by the CrashReporterHost) and exception-time specific ones. The resulting annotations are slightly different than before the patch: first of all there are no more duplicate entries in the .extra file and secondly all content/plugin process hangs annotations are properly filtered, before annotations that were main process-only would leak into them. Differential Revision: https://phabricator.services.mozilla.com/D31069 --HG-- extra : moz-landing-system : lando
2019-05-18 19:19:55 +03:00
return crashDump;
}
Bug 1547698 - Refactor the code that writes the .extra file for a content process crash or hang r=froydnj Upon a content process crash or hang crash annotations were incrementally written into the .extra file starting with the exception handler callback and then in a number of different places before the file was ready for submission. This had a number of downsides: since the annotations were directly added to the file it was impossible to tell which ones were already written at a certain point in time, additionally some were written twice or even thrice. The code doing the writing would also behave differently depending on the contents of the file, the parameters passed to it and the contents of global variables. This change overhauls the whole process by keeping the annotations into a temporary per-crash annotation table which is filled with all the required annotations before being written out in a single pass when they are ready. The annotations are gathered from the main process annotation table, the per-process one (held by the CrashReporterHost) and exception-time specific ones. The resulting annotations are slightly different than before the patch: first of all there are no more duplicate entries in the .extra file and secondly all content/plugin process hangs annotations are properly filtered, before annotations that were main process-only would leak into them. Differential Revision: https://phabricator.services.mozilla.com/D31069 --HG-- extra : moz-landing-system : lando
2019-05-18 19:19:55 +03:00
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());
Bug 1614933 - Gather content processes' crash annotations at exception time instead of using IPC; r=froydnj Crash annotations in content processes are currently sent over IPC via shared memory buffers. To pave the way for the Rust rewrite of the exception handler we are removing this code and gathering all the crash annotations within the content processes themselves. This patch causes annotations to be stored in the global table of each content process. They are then streamed out to the parent process by the exception handler together with the exception-time annotations. This has a number of benefits: * we have one less channel to exchange data between content processes and the parent process * we save memory because we don't need to allocate the shared memory buffers * annotations are faster because we don't stream them all out every time one changes * we won't truncate annotations anymore if we run out of space in the shared segment. * we don't need delayed annotations anymore, so we can get rid of the associated machinery As I refactored the code I tried to adjust all the obsolete comments, consolidate shared code and remove the redundant steps that were sometimes present. In many places we had two entire crash annotation tables we merged to change just a couple; that comes from the fact that historically we loaded them from disk. Now it doesn't matter anymore and we can just go ahead and change the ones we care about. Differential Revision: https://phabricator.services.mozilla.com/D62586 --HG-- extra : moz-landing-system : lando
2020-04-08 09:55:40 +03:00
mExtraAnnotations[CrashReporter::Annotation::ProcessType] =
XRE_ChildProcessTypeToAnnotation(mProcessType);
char startTime[32];
SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
Bug 1614933 - Gather content processes' crash annotations at exception time instead of using IPC; r=froydnj Crash annotations in content processes are currently sent over IPC via shared memory buffers. To pave the way for the Rust rewrite of the exception handler we are removing this code and gathering all the crash annotations within the content processes themselves. This patch causes annotations to be stored in the global table of each content process. They are then streamed out to the parent process by the exception handler together with the exception-time annotations. This has a number of benefits: * we have one less channel to exchange data between content processes and the parent process * we save memory because we don't need to allocate the shared memory buffers * annotations are faster because we don't stream them all out every time one changes * we won't truncate annotations anymore if we run out of space in the shared segment. * we don't need delayed annotations anymore, so we can get rid of the associated machinery As I refactored the code I tried to adjust all the obsolete comments, consolidate shared code and remove the redundant steps that were sometimes present. In many places we had two entire crash annotation tables we merged to change just a couple; that comes from the fact that historically we loaded them from disk. Now it doesn't matter anymore and we can just go ahead and change the ones we care about. Differential Revision: https://phabricator.services.mozilla.com/D62586 --HG-- extra : moz-landing-system : lando
2020-04-08 09:55:40 +03:00
mExtraAnnotations[CrashReporter::Annotation::StartupTime] =
nsDependentCString(startTime);
Bug 1547698 - Refactor the code that writes the .extra file for a content process crash or hang r=froydnj Upon a content process crash or hang crash annotations were incrementally written into the .extra file starting with the exception handler callback and then in a number of different places before the file was ready for submission. This had a number of downsides: since the annotations were directly added to the file it was impossible to tell which ones were already written at a certain point in time, additionally some were written twice or even thrice. The code doing the writing would also behave differently depending on the contents of the file, the parameters passed to it and the contents of global variables. This change overhauls the whole process by keeping the annotations into a temporary per-crash annotation table which is filled with all the required annotations before being written out in a single pass when they are ready. The annotations are gathered from the main process annotation table, the per-process one (held by the CrashReporterHost) and exception-time specific ones. The resulting annotations are slightly different than before the patch: first of all there are no more duplicate entries in the .extra file and secondly all content/plugin process hangs annotations are properly filtered, before annotations that were main process-only would leak into them. Differential Revision: https://phabricator.services.mozilla.com/D31069 --HG-- extra : moz-landing-system : lando
2019-05-18 19:19:55 +03:00
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));
}
Bug 1831092 - Use the new pull-based API for all crash annotations and remove the global annotations table r=jgilbert,necko-reviewers,media-playback-reviewers,profiler-reviewers,win-reviewers,padenot,handyman,afranchuk,valentin,alwu,sotaro This changes comes with several different refactorings all rolled into one, unfotunately I couldn't find a way to pull them apart: - First of all annotations now can either recorded (that is, we copy the value and have the crash reporting code own the copy) or registered. Several annotations are changed to use this functionality so that we don't need to update them as their value change. - The code in the exception handler is modified to read the annotations from the mozannotation_client crate. This has the unfortunate side-effect that we need three different bits of code to serialize them: one for annotations read from a child process, one for reading annotations from the main process outside of the exception handler and one for reading annotations from the main process within the exception handler. As we move to fully out-of-process crash reporting the last two methods will go away. - The mozannotation_client crate now doesn't record annotation types anymore. I realized as I was working on this that storing types at runtime has two issues: the first one is that buggy code might change the type of an annotation (that is record it under two different types at two different moments), the second issue is that types might become corrupt during a crash, so better enforce them at annotation-writing time. The end result is that the mozannotation_* crates now only store byte buffers, track the format the data is stored in (null-terminated string, fixed size buffer, etc...) but not the type of data each annotation is supposed to contain. - Which brings us to the next change: concrete types for annotations are now enforced when they're written out. If an annotation doesn't match the expected type it's skipped. Storing an annotation with the wrong type will also trigger an assertion in debug builds. Differential Revision: https://phabricator.services.mozilla.com/D195248
2024-03-04 13:24:43 +03:00
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;
}
Bug 1831092 - Use the new pull-based API for all crash annotations and remove the global annotations table r=jgilbert,necko-reviewers,media-playback-reviewers,profiler-reviewers,win-reviewers,padenot,handyman,afranchuk,valentin,alwu,sotaro This changes comes with several different refactorings all rolled into one, unfotunately I couldn't find a way to pull them apart: - First of all annotations now can either recorded (that is, we copy the value and have the crash reporting code own the copy) or registered. Several annotations are changed to use this functionality so that we don't need to update them as their value change. - The code in the exception handler is modified to read the annotations from the mozannotation_client crate. This has the unfortunate side-effect that we need three different bits of code to serialize them: one for annotations read from a child process, one for reading annotations from the main process outside of the exception handler and one for reading annotations from the main process within the exception handler. As we move to fully out-of-process crash reporting the last two methods will go away. - The mozannotation_client crate now doesn't record annotation types anymore. I realized as I was working on this that storing types at runtime has two issues: the first one is that buggy code might change the type of an annotation (that is record it under two different types at two different moments), the second issue is that types might become corrupt during a crash, so better enforce them at annotation-writing time. The end result is that the mozannotation_* crates now only store byte buffers, track the format the data is stored in (null-terminated string, fixed size buffer, etc...) but not the type of data each annotation is supposed to contain. - Which brings us to the next change: concrete types for annotations are now enforced when they're written out. If an annotation doesn't match the expected type it's skipped. Storing an annotation with the wrong type will also trigger an assertion in debug builds. Differential Revision: https://phabricator.services.mozilla.com/D195248
2024-03-04 13:24:43 +03:00
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;
}
Bug 1831092 - Use the new pull-based API for all crash annotations and remove the global annotations table r=jgilbert,necko-reviewers,media-playback-reviewers,profiler-reviewers,win-reviewers,padenot,handyman,afranchuk,valentin,alwu,sotaro This changes comes with several different refactorings all rolled into one, unfotunately I couldn't find a way to pull them apart: - First of all annotations now can either recorded (that is, we copy the value and have the crash reporting code own the copy) or registered. Several annotations are changed to use this functionality so that we don't need to update them as their value change. - The code in the exception handler is modified to read the annotations from the mozannotation_client crate. This has the unfortunate side-effect that we need three different bits of code to serialize them: one for annotations read from a child process, one for reading annotations from the main process outside of the exception handler and one for reading annotations from the main process within the exception handler. As we move to fully out-of-process crash reporting the last two methods will go away. - The mozannotation_client crate now doesn't record annotation types anymore. I realized as I was working on this that storing types at runtime has two issues: the first one is that buggy code might change the type of an annotation (that is record it under two different types at two different moments), the second issue is that types might become corrupt during a crash, so better enforce them at annotation-writing time. The end result is that the mozannotation_* crates now only store byte buffers, track the format the data is stored in (null-terminated string, fixed size buffer, etc...) but not the type of data each annotation is supposed to contain. - Which brings us to the next change: concrete types for annotations are now enforced when they're written out. If an annotation doesn't match the expected type it's skipped. Storing an annotation with the wrong type will also trigger an assertion in debug builds. Differential Revision: https://phabricator.services.mozilla.com/D195248
2024-03-04 13:24:43 +03:00
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