1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "CrashReporterHost.h"
8 #include "mozilla/dom/Promise.h"
9 #include "mozilla/Sprintf.h"
10 #include "mozilla/SyncRunnable.h"
11 #include "mozilla/Telemetry.h"
12 #include "nsServiceManagerUtils.h"
13 #include "nsICrashService.h"
14 #include "nsXULAppAPI.h"
20 CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType
,
21 CrashReporter::ThreadId aThreadId
)
22 : mProcessType(aProcessType
),
24 mStartTime(::time(nullptr)),
27 bool CrashReporterHost::GenerateCrashReport(base::ProcessId aPid
) {
28 if (!TakeCrashedChildMinidump(aPid
, nullptr)) {
31 return FinalizeCrashReport();
34 RefPtr
<nsIFile
> CrashReporterHost::TakeCrashedChildMinidump(
35 base::ProcessId aPid
, uint32_t* aOutSequence
) {
36 CrashReporter::AnnotationTable annotations
;
37 MOZ_ASSERT(!HasMinidump());
39 RefPtr
<nsIFile
> crashDump
;
40 if (!CrashReporter::TakeMinidumpForChild(aPid
, getter_AddRefs(crashDump
),
41 annotations
, aOutSequence
)) {
44 if (!AdoptMinidump(crashDump
, annotations
)) {
50 bool CrashReporterHost::AdoptMinidump(nsIFile
* aFile
,
51 const AnnotationTable
& aAnnotations
) {
52 if (!CrashReporter::GetIDFromMinidump(aFile
, mDumpID
)) {
56 MergeCrashAnnotations(mExtraAnnotations
, aAnnotations
);
60 bool CrashReporterHost::FinalizeCrashReport() {
61 MOZ_ASSERT(!mFinalized
);
62 MOZ_ASSERT(HasMinidump());
64 mExtraAnnotations
[CrashReporter::Annotation::ProcessType
] =
65 XRE_ChildProcessTypeToAnnotation(mProcessType
);
68 SprintfLiteral(startTime
, "%lld", static_cast<long long>(mStartTime
));
69 mExtraAnnotations
[CrashReporter::Annotation::StartupTime
] =
70 nsDependentCString(startTime
);
72 CrashReporter::WriteExtraFile(mDumpID
, mExtraAnnotations
);
74 RecordCrash(mProcessType
, nsICrashService::CRASH_TYPE_CRASH
, mDumpID
);
81 void CrashReporterHost::RecordCrash(GeckoProcessType aProcessType
,
83 const nsString
& aChildDumpID
) {
84 if (!NS_IsMainThread()) {
85 RefPtr
<Runnable
> runnable
= NS_NewRunnableFunction(
86 "ipc::CrashReporterHost::RecordCrash", [&]() -> void {
87 CrashReporterHost::RecordCrash(aProcessType
, aCrashType
,
90 RefPtr
<nsIThread
> mainThread
= do_GetMainThread();
91 SyncRunnable::DispatchToThread(mainThread
, runnable
);
95 RecordCrashWithTelemetry(aProcessType
, aCrashType
);
96 NotifyCrashService(aProcessType
, aCrashType
, aChildDumpID
);
100 void CrashReporterHost::RecordCrashWithTelemetry(GeckoProcessType aProcessType
,
101 int32_t aCrashType
) {
104 switch (aProcessType
) {
105 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \
106 process_bin_type, procinfo_typename, \
107 webidl_typename, allcaps_name) \
108 case GeckoProcessType_##enum_name: \
109 key.AssignLiteral(string_name); \
111 #include "mozilla/GeckoProcessTypes.h"
112 #undef GECKO_PROCESS_TYPE
113 // We can't really hit this, thanks to the above switch, but having it
114 // here will placate the compiler.
116 MOZ_ASSERT_UNREACHABLE("unknown process type");
119 Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP
, key
, 1);
123 void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType
,
125 const nsString
& aChildDumpID
) {
126 MOZ_ASSERT(!aChildDumpID
.IsEmpty());
128 nsCOMPtr
<nsICrashService
> crashService
=
129 do_GetService("@mozilla.org/crashservice;1");
136 switch (aProcessType
) {
137 case GeckoProcessType_IPDLUnitTest
:
138 case GeckoProcessType_Default
:
139 NS_ERROR("unknown process type");
142 processType
= (int)aProcessType
;
146 RefPtr
<dom::Promise
> promise
;
147 crashService
->AddCrash(processType
, aCrashType
, aChildDumpID
,
148 getter_AddRefs(promise
));
151 void CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey
,
153 mExtraAnnotations
[aKey
] = aValue
? "1"_ns
: "0"_ns
;
156 void CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey
,
158 nsAutoCString valueString
;
159 valueString
.AppendInt(aValue
);
160 mExtraAnnotations
[aKey
] = valueString
;
163 void CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey
,
164 unsigned int aValue
) {
165 nsAutoCString valueString
;
166 valueString
.AppendInt(aValue
);
167 mExtraAnnotations
[aKey
] = valueString
;
170 void CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey
,
171 const nsACString
& aValue
) {
172 mExtraAnnotations
[aKey
] = aValue
;
175 bool CrashReporterHost::IsLikelyOOM() {
176 // The data is only populated during the call to `FinalizeCrashReport()`.
177 MOZ_ASSERT(mFinalized
);
179 // If `OOMAllocationSize` was set, we know that the crash happened
180 // because an allocation failed (`malloc` returned `nullptr`).
182 // As Unix systems generally allow `malloc` to return a non-null value
183 // even when no virtual memory is available, this doesn't cover all
184 // cases of OOM under Unix (far from it).
185 return mExtraAnnotations
[CrashReporter::Annotation::OOMAllocationSize
]
190 } // namespace mozilla