Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/ipc/glue/CrashReporterHost.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "CrashReporterHost.h"
8
#include "CrashReporterMetadataShmem.h"
9
#include "mozilla/dom/Promise.h"
10
#include "mozilla/recordreplay/ParentIPC.h"
11
#include "mozilla/Sprintf.h"
12
#include "mozilla/SyncRunnable.h"
13
#include "mozilla/Telemetry.h"
14
#include "nsIAsyncShutdown.h"
15
#include "nsICrashService.h"
16
17
namespace mozilla {
18
namespace ipc {
19
20
CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
21
                                     const Shmem& aShmem,
22
                                     CrashReporter::ThreadId aThreadId)
23
 : mProcessType(aProcessType),
24
   mShmem(aShmem),
25
   mThreadId(aThreadId),
26
   mStartTime(::time(nullptr)),
27
   mFinalized(false)
28
0
{
29
0
}
30
31
bool
32
CrashReporterHost::GenerateCrashReport(base::ProcessId aPid)
33
0
{
34
0
  if (!TakeCrashedChildMinidump(aPid, nullptr)) {
35
0
    return false;
36
0
  }
37
0
  return FinalizeCrashReport();
38
0
}
39
40
RefPtr<nsIFile>
41
CrashReporterHost::TakeCrashedChildMinidump(base::ProcessId aPid, uint32_t* aOutSequence)
42
0
{
43
0
  MOZ_ASSERT(!HasMinidump());
44
0
45
0
  RefPtr<nsIFile> crashDump;
46
0
  if (!XRE_TakeMinidumpForChild(aPid, getter_AddRefs(crashDump), aOutSequence)) {
47
0
    return nullptr;
48
0
  }
49
0
  if (!AdoptMinidump(crashDump)) {
50
0
    return nullptr;
51
0
  }
52
0
  return crashDump.get();
53
0
}
54
55
bool
56
CrashReporterHost::AdoptMinidump(nsIFile* aFile)
57
0
{
58
0
  return CrashReporter::GetIDFromMinidump(aFile, mDumpID);
59
0
}
60
61
int32_t
62
CrashReporterHost::GetCrashType(const CrashReporter::AnnotationTable& aAnnotations)
63
0
{
64
0
  // RecordReplayHang is set in the middleman content process, so check aAnnotations.
65
0
  if (aAnnotations[CrashReporter::Annotation::RecordReplayHang].EqualsLiteral("1")) {
66
0
    return nsICrashService::CRASH_TYPE_HANG;
67
0
  }
68
0
69
0
  // PluginHang is set in the parent process, so check mExtraAnnotations.
70
0
  if (mExtraAnnotations[CrashReporter::Annotation::PluginHang].EqualsLiteral("1")) {
71
0
    return nsICrashService::CRASH_TYPE_HANG;
72
0
  }
73
0
74
0
  return nsICrashService::CRASH_TYPE_CRASH;
75
0
}
76
77
bool
78
CrashReporterHost::FinalizeCrashReport()
79
0
{
80
0
  MOZ_ASSERT(!mFinalized);
81
0
  MOZ_ASSERT(HasMinidump());
82
0
83
0
  CrashReporter::AnnotationTable annotations;
84
0
85
0
  nsAutoCString type;
86
0
  switch (mProcessType) {
87
0
    case GeckoProcessType_Content:
88
0
      type = NS_LITERAL_CSTRING("content");
89
0
      break;
90
0
    case GeckoProcessType_Plugin:
91
0
    case GeckoProcessType_GMPlugin:
92
0
      type = NS_LITERAL_CSTRING("plugin");
93
0
      break;
94
0
    case GeckoProcessType_GPU:
95
0
      type = NS_LITERAL_CSTRING("gpu");
96
0
      break;
97
0
    default:
98
0
      NS_ERROR("unknown process type");
99
0
      break;
100
0
  }
101
0
  annotations[CrashReporter::Annotation::ProcessType] = type;
102
0
103
0
  char startTime[32];
104
0
  SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime));
105
0
  annotations[CrashReporter::Annotation::StartupTime] =
106
0
    nsDependentCString(startTime);
107
0
108
0
  // We might not have shmem (for example, when running crashreporter tests).
109
0
  if (mShmem.IsReadable()) {
110
0
    CrashReporterMetadataShmem::ReadAppNotes(mShmem, annotations);
111
0
  }
112
0
  CrashReporter::AppendExtraData(mDumpID, mExtraAnnotations);
113
0
  CrashReporter::AppendExtraData(mDumpID, annotations);
114
0
115
0
  int32_t crashType = GetCrashType(annotations);
116
0
  NotifyCrashService(mProcessType, crashType, mDumpID);
117
0
118
0
  mFinalized = true;
119
0
  return true;
120
0
}
121
122
/* static */ void
123
CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType,
124
                                      int32_t aCrashType,
125
                                      const nsString& aChildDumpID)
126
0
{
127
0
  if (!NS_IsMainThread()) {
128
0
    RefPtr<Runnable> runnable = NS_NewRunnableFunction(
129
0
      "ipc::CrashReporterHost::NotifyCrashService", [&]() -> void {
130
0
        CrashReporterHost::NotifyCrashService(aProcessType, aCrashType, aChildDumpID);
131
0
      });
132
0
    RefPtr<nsIThread> mainThread = do_GetMainThread();
133
0
    SyncRunnable::DispatchToThread(mainThread, runnable);
134
0
    return;
135
0
  }
136
0
137
0
  MOZ_ASSERT(!aChildDumpID.IsEmpty());
138
0
139
0
  nsCOMPtr<nsICrashService> crashService =
140
0
    do_GetService("@mozilla.org/crashservice;1");
141
0
  if (!crashService) {
142
0
    return;
143
0
  }
144
0
145
0
  int32_t processType;
146
0
  nsCString telemetryKey;
147
0
148
0
  switch (aProcessType) {
149
0
    case GeckoProcessType_Content:
150
0
      processType = nsICrashService::PROCESS_TYPE_CONTENT;
151
0
      telemetryKey.AssignLiteral("content");
152
0
      break;
153
0
    case GeckoProcessType_Plugin:
154
0
      processType = nsICrashService::PROCESS_TYPE_PLUGIN;
155
0
      if (aCrashType == nsICrashService::CRASH_TYPE_HANG) {
156
0
        telemetryKey.AssignLiteral("pluginhang");
157
0
      } else {
158
0
        telemetryKey.AssignLiteral("plugin");
159
0
      }
160
0
      break;
161
0
    case GeckoProcessType_GMPlugin:
162
0
      processType = nsICrashService::PROCESS_TYPE_GMPLUGIN;
163
0
      telemetryKey.AssignLiteral("gmplugin");
164
0
      break;
165
0
    case GeckoProcessType_GPU:
166
0
      processType = nsICrashService::PROCESS_TYPE_GPU;
167
0
      telemetryKey.AssignLiteral("gpu");
168
0
      break;
169
0
    default:
170
0
      NS_ERROR("unknown process type");
171
0
      return;
172
0
  }
173
0
174
0
  RefPtr<Promise> promise;
175
0
  crashService->AddCrash(processType, aCrashType, aChildDumpID, getter_AddRefs(promise));
176
0
  Telemetry::Accumulate(Telemetry::SUBPROCESS_CRASHES_WITH_DUMP, telemetryKey, 1);
177
0
}
178
179
void
180
CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey, bool aValue)
181
0
{
182
0
  mExtraAnnotations[aKey] = aValue ? NS_LITERAL_CSTRING("1")
183
0
                                   : NS_LITERAL_CSTRING("0");
184
0
}
185
186
void
187
CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey,
188
                                 int aValue)
189
0
{
190
0
  nsAutoCString valueString;
191
0
  valueString.AppendInt(aValue);
192
0
  mExtraAnnotations[aKey] = valueString;
193
0
}
194
195
void
196
CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey,
197
                                 unsigned int aValue)
198
0
{
199
0
  nsAutoCString valueString;
200
0
  valueString.AppendInt(aValue);
201
0
  mExtraAnnotations[aKey] = valueString;
202
0
}
203
204
void
205
CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey,
206
                                 const nsCString& aValue)
207
0
{
208
0
  mExtraAnnotations[aKey] = aValue;
209
0
}
210
211
} // namespace ipc
212
} // namespace mozilla