OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "handler/handler_main.h" | 15 #include "handler/handler_main.h" |
16 | 16 |
17 #include <errno.h> | 17 #include <errno.h> |
18 #include <getopt.h> | 18 #include <getopt.h> |
19 #include <stdint.h> | 19 #include <stdint.h> |
20 #include <stdlib.h> | 20 #include <stdlib.h> |
21 #include <sys/types.h> | 21 #include <sys/types.h> |
22 | 22 |
23 #include <map> | 23 #include <map> |
24 #include <memory> | 24 #include <memory> |
25 #include <string> | 25 #include <string> |
26 #include <utility> | 26 #include <utility> |
| 27 #include <vector> |
27 | 28 |
28 #include "base/auto_reset.h" | 29 #include "base/auto_reset.h" |
| 30 #include "base/compiler_specific.h" |
29 #include "base/files/file_path.h" | 31 #include "base/files/file_path.h" |
30 #include "base/files/scoped_file.h" | 32 #include "base/files/scoped_file.h" |
31 #include "base/logging.h" | 33 #include "base/logging.h" |
32 #include "base/metrics/persistent_histogram_allocator.h" | 34 #include "base/metrics/persistent_histogram_allocator.h" |
33 #include "base/scoped_generic.h" | 35 #include "base/scoped_generic.h" |
34 #include "base/strings/utf_string_conversions.h" | 36 #include "base/strings/utf_string_conversions.h" |
35 #include "build/build_config.h" | 37 #include "build/build_config.h" |
36 #include "client/crash_report_database.h" | 38 #include "client/crash_report_database.h" |
37 #include "client/crashpad_client.h" | 39 #include "client/crashpad_client.h" |
38 #include "client/prune_crash_reports.h" | 40 #include "client/prune_crash_reports.h" |
(...skipping 18 matching lines...) Expand all Loading... |
57 #include "util/mach/child_port_handshake.h" | 59 #include "util/mach/child_port_handshake.h" |
58 #include "util/mach/mach_extensions.h" | 60 #include "util/mach/mach_extensions.h" |
59 #include "util/posix/close_stdio.h" | 61 #include "util/posix/close_stdio.h" |
60 #elif defined(OS_WIN) | 62 #elif defined(OS_WIN) |
61 #include <windows.h> | 63 #include <windows.h> |
62 | 64 |
63 #include "handler/win/crash_report_exception_handler.h" | 65 #include "handler/win/crash_report_exception_handler.h" |
64 #include "util/win/exception_handler_server.h" | 66 #include "util/win/exception_handler_server.h" |
65 #include "util/win/handle.h" | 67 #include "util/win/handle.h" |
66 #include "util/win/initial_client_data.h" | 68 #include "util/win/initial_client_data.h" |
| 69 #include "util/win/session_end_watcher.h" |
67 #endif // OS_MACOSX | 70 #endif // OS_MACOSX |
68 | 71 |
69 namespace crashpad { | 72 namespace crashpad { |
70 | 73 |
71 namespace { | 74 namespace { |
72 | 75 |
73 void Usage(const base::FilePath& me) { | 76 void Usage(const base::FilePath& me) { |
74 fprintf(stderr, | 77 fprintf(stderr, |
75 "Usage: %" PRFilePath " [OPTION]...\n" | 78 "Usage: %" PRFilePath " [OPTION]...\n" |
76 "Crashpad's exception handler server.\n" | 79 "Crashpad's exception handler server.\n" |
77 "\n" | 80 "\n" |
78 " --annotation=KEY=VALUE set a process annotation in each crash report\n" | 81 " --annotation=KEY=VALUE set a process annotation in each crash report\n" |
79 " --database=PATH store the crash report database at PATH\n" | 82 " --database=PATH store the crash report database at PATH\n" |
80 #if defined(OS_MACOSX) | 83 #if defined(OS_MACOSX) |
81 " --handshake-fd=FD establish communication with the client over FD\n
" | 84 " --handshake-fd=FD establish communication with the client over FD\n
" |
82 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" | 85 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" |
83 #elif defined(OS_WIN) | 86 #elif defined(OS_WIN) |
84 " --initial-client-data=HANDLE_request_crash_dump,\n" | 87 " --initial-client-data=HANDLE_request_crash_dump,\n" |
85 " HANDLE_request_non_crash_dump,\n" | 88 " HANDLE_request_non_crash_dump,\n" |
86 " HANDLE_non_crash_dump_completed,\n" | 89 " HANDLE_non_crash_dump_completed,\n" |
87 " HANDLE_pipe,\n" | 90 " HANDLE_pipe,\n" |
88 " HANDLE_client_process,\n" | 91 " HANDLE_client_process,\n" |
89 " Address_crash_exception_information,\n" | 92 " Address_crash_exception_information,\n" |
90 " Address_non_crash_exception_information,\n" | 93 " Address_non_crash_exception_information,\n" |
91 " Address_debug_critical_section\n" | 94 " Address_debug_critical_section\n" |
92 " use precreated data to register initial client\n" | 95 " use precreated data to register initial client\n" |
93 #endif // OS_MACOSX | 96 #endif // OS_MACOSX |
94 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" | 97 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" |
95 " --no-rate-limit don't rate limit crash uploads\n" | 98 " --no-rate-limit don't rate limit crash uploads\n" |
| 99 " --no-upload-gzip don't use gzip compression when uploading\n" |
96 #if defined(OS_MACOSX) | 100 #if defined(OS_MACOSX) |
97 " --reset-own-crash-exception-port-to-system-default\n" | 101 " --reset-own-crash-exception-port-to-system-default\n" |
98 " reset the server's exception handler to default\n
" | 102 " reset the server's exception handler to default\n
" |
99 #elif defined(OS_WIN) | 103 #elif defined(OS_WIN) |
100 " --pipe-name=PIPE communicate with the client over PIPE\n" | 104 " --pipe-name=PIPE communicate with the client over PIPE\n" |
101 #endif // OS_MACOSX | 105 #endif // OS_MACOSX |
102 " --url=URL send crash reports to this Breakpad server URL,\n
" | 106 " --url=URL send crash reports to this Breakpad server URL,\n
" |
103 " only if uploads are enabled for the database\n" | 107 " only if uploads are enabled for the database\n" |
104 " --help display this help and exit\n" | 108 " --help display this help and exit\n" |
105 " --version output version information and exit\n", | 109 " --version output version information and exit\n", |
106 me.value().c_str()); | 110 me.value().c_str()); |
107 ToolSupport::UsageTail(me); | 111 ToolSupport::UsageTail(me); |
108 } | 112 } |
109 | 113 |
| 114 // Calls Metrics::HandlerLifetimeMilestone, but only on the first call. This is |
| 115 // to prevent multiple exit events from inadvertently being recorded, which |
| 116 // might happen if a crash occurs during destruction in what would otherwise be |
| 117 // a normal exit, or if a CallMetricsRecordNormalExit object is destroyed after |
| 118 // something else logs an exit event. |
| 119 void MetricsRecordExit(Metrics::LifetimeMilestone milestone) { |
| 120 static bool once = [](Metrics::LifetimeMilestone milestone) { |
| 121 Metrics::HandlerLifetimeMilestone(milestone); |
| 122 return true; |
| 123 }(milestone); |
| 124 ALLOW_UNUSED_LOCAL(once); |
| 125 } |
| 126 |
| 127 // Calls MetricsRecordExit() to record a failure, and returns EXIT_FAILURE for |
| 128 // the convenience of callers in main() which can simply write “return |
| 129 // ExitFailure();”. |
| 130 int ExitFailure() { |
| 131 MetricsRecordExit(Metrics::LifetimeMilestone::kFailed); |
| 132 return EXIT_FAILURE; |
| 133 } |
| 134 |
| 135 class CallMetricsRecordNormalExit { |
| 136 public: |
| 137 CallMetricsRecordNormalExit() {} |
| 138 ~CallMetricsRecordNormalExit() { |
| 139 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedNormally); |
| 140 } |
| 141 |
| 142 private: |
| 143 DISALLOW_COPY_AND_ASSIGN(CallMetricsRecordNormalExit); |
| 144 }; |
| 145 |
110 #if defined(OS_MACOSX) | 146 #if defined(OS_MACOSX) |
111 | 147 |
112 struct sigaction g_original_crash_sigaction[NSIG]; | 148 void InstallSignalHandler(const std::vector<int>& signals, |
| 149 void (*handler)(int, siginfo_t*, void*)) { |
| 150 struct sigaction sa = {}; |
| 151 sigemptyset(&sa.sa_mask); |
| 152 sa.sa_flags = SA_SIGINFO; |
| 153 sa.sa_sigaction = handler; |
| 154 |
| 155 for (int sig : signals) { |
| 156 int rv = sigaction(sig, &sa, nullptr); |
| 157 PCHECK(rv == 0) << "sigaction " << sig; |
| 158 } |
| 159 } |
| 160 |
| 161 void RestoreDefaultSignalHandler(int sig) { |
| 162 struct sigaction sa = {}; |
| 163 sigemptyset(&sa.sa_mask); |
| 164 sa.sa_flags = 0; |
| 165 sa.sa_handler = SIG_DFL; |
| 166 int rv = sigaction(sig, &sa, nullptr); |
| 167 DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; |
| 168 ALLOW_UNUSED_LOCAL(rv); |
| 169 } |
113 | 170 |
114 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { | 171 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) { |
| 172 MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); |
| 173 |
115 // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not | 174 // Is siginfo->si_code useful? The only interesting values on macOS are 0 (not |
116 // useful, signals generated asynchronously such as by kill() or raise()) and | 175 // useful, signals generated asynchronously such as by kill() or raise()) and |
117 // small positive numbers (useful, signal generated via a hardware fault). The | 176 // small positive numbers (useful, signal generated via a hardware fault). The |
118 // standard specifies these other constants, and while xnu never uses them, | 177 // standard specifies these other constants, and while xnu never uses them, |
119 // they are intended to denote signals generated asynchronously and are | 178 // they are intended to denote signals generated asynchronously and are |
120 // included here. Additionally, existing practice on other systems | 179 // included here. Additionally, existing practice on other systems |
121 // (acknowledged by the standard) is for negative numbers to indicate that a | 180 // (acknowledged by the standard) is for negative numbers to indicate that a |
122 // signal was generated asynchronously. Although xnu does not do this, allow | 181 // signal was generated asynchronously. Although xnu does not do this, allow |
123 // for the possibility for completeness. | 182 // for the possibility for completeness. |
124 bool si_code_valid = !(siginfo->si_code <= 0 || | 183 bool si_code_valid = !(siginfo->si_code <= 0 || |
(...skipping 11 matching lines...) Expand all Loading... |
136 // without a Mach exception. Furthermore, it does not allow siginfo->si_code | 195 // without a Mach exception. Furthermore, it does not allow siginfo->si_code |
137 // to be encoded, because that’s not available to Mach exception handlers. It | 196 // to be encoded, because that’s not available to Mach exception handlers. It |
138 // would be a shame to lose that information available to a POSIX signal | 197 // would be a shame to lose that information available to a POSIX signal |
139 // handler. | 198 // handler. |
140 int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8); | 199 int metrics_code = 0x53430000 | (InRangeCast<uint8_t>(sig, 0xff) << 8); |
141 if (si_code_valid) { | 200 if (si_code_valid) { |
142 metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff); | 201 metrics_code |= InRangeCast<uint8_t>(siginfo->si_code, 0xff); |
143 } | 202 } |
144 Metrics::HandlerCrashed(metrics_code); | 203 Metrics::HandlerCrashed(metrics_code); |
145 | 204 |
146 // Restore the previous signal handler. | 205 RestoreDefaultSignalHandler(sig); |
147 DCHECK_GT(sig, 0); | |
148 DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | |
149 struct sigaction* osa = &g_original_crash_sigaction[sig]; | |
150 int rv = sigaction(sig, osa, nullptr); | |
151 DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig; | |
152 | 206 |
153 // If the signal was received synchronously resulting from a hardware fault, | 207 // If the signal was received synchronously resulting from a hardware fault, |
154 // returning from the signal handler will cause the kernel to re-raise it, | 208 // returning from the signal handler will cause the kernel to re-raise it, |
155 // because this handler hasn’t done anything to alleviate the condition that | 209 // because this handler hasn’t done anything to alleviate the condition that |
156 // caused the signal to be raised in the first place. With the old signal | 210 // caused the signal to be raised in the first place. With the default signal |
157 // handler in place (expected to be SIG_DFL), it will cause the same behavior | 211 // handler in place, it will cause the same behavior to be taken as though |
158 // to be taken as though this signal handler had never been installed at all | 212 // this signal handler had never been installed at all (expected to be a |
159 // (expected to be a crash). This is ideal, because the signal is re-raised | 213 // crash). This is ideal, because the signal is re-raised with the same |
160 // with the same properties and from the same context that initially triggered | 214 // properties and from the same context that initially triggered it, providing |
161 // it, providing the best debugging experience. | 215 // the best debugging experience. |
162 | 216 |
163 if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || | 217 if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) || |
164 !si_code_valid) { | 218 !si_code_valid) { |
165 // Signals received other than via hardware faults, such as those raised | 219 // Signals received other than via hardware faults, such as those raised |
166 // asynchronously via kill() and raise(), and those arising via hardware | 220 // asynchronously via kill() and raise(), and those arising via hardware |
167 // traps such as int3 (resulting in SIGTRAP but advancing the instruction | 221 // traps such as int3 (resulting in SIGTRAP but advancing the instruction |
168 // pointer), will not reoccur on their own when returning from the signal | 222 // pointer), will not reoccur on their own when returning from the signal |
169 // handler. Re-raise them or call to the previous signal handler as | 223 // handler. Re-raise them. |
170 // appropriate. | |
171 // | 224 // |
172 // Unfortunately, when SIGBUS is received asynchronously via kill(), | 225 // Unfortunately, when SIGBUS is received asynchronously via kill(), |
173 // siginfo->si_code makes it appear as though it was actually received via a | 226 // siginfo->si_code makes it appear as though it was actually received via a |
174 // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c | 227 // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c |
175 // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed | 228 // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed |
176 // metric to be logged but will not cause the process to terminate. This | 229 // metric to be logged but will not cause the process to terminate. This |
177 // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The | 230 // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The |
178 // alternative, to re-raise here on any SIGBUS, is a bad idea because it | 231 // alternative, to re-raise here on any SIGBUS, is a bad idea because it |
179 // would lose properties associated with the the original signal, which are | 232 // would lose properties associated with the the original signal, which are |
180 // very valuable for debugging and are visible to a Mach exception handler. | 233 // very valuable for debugging and are visible to a Mach exception handler. |
181 // Since SIGBUS is normally received synchronously in response to a hardware | 234 // Since SIGBUS is normally received synchronously in response to a hardware |
182 // fault, don’t sweat the unexpected asynchronous case. | 235 // fault, don’t sweat the unexpected asynchronous case. |
183 if (osa->sa_handler == SIG_DFL) { | 236 // |
184 // Because this signal handler executes with the signal blocked, this | 237 // Because this signal handler executes with the signal blocked, this |
185 // raise() cannot immediately deliver the signal. Delivery is deferred | 238 // raise() cannot immediately deliver the signal. Delivery is deferred until |
186 // until this signal handler returns and the signal becomes unblocked. The | 239 // this signal handler returns and the signal becomes unblocked. The |
187 // re-raised signal will appear with the same context as where it was | 240 // re-raised signal will appear with the same context as where it was |
188 // initially triggered. | 241 // initially triggered. |
189 rv = raise(sig); | 242 int rv = raise(sig); |
190 DPLOG_IF(ERROR, rv != 0) << "raise"; | 243 DPLOG_IF(ERROR, rv != 0) << "raise"; |
191 } else if (osa->sa_handler != SIG_IGN) { | 244 ALLOW_UNUSED_LOCAL(rv); |
192 if (osa->sa_flags & SA_SIGINFO) { | |
193 osa->sa_sigaction(sig, siginfo, context); | |
194 } else { | |
195 osa->sa_handler(sig); | |
196 } | |
197 } | |
198 } | 245 } |
199 } | 246 } |
200 | 247 |
| 248 void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) { |
| 249 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
| 250 |
| 251 RestoreDefaultSignalHandler(sig); |
| 252 |
| 253 // Re-raise the signal. See the explanation in HandleCrashSignal(). Note that |
| 254 // no checks for signals arising from synchronous hardware faults are made |
| 255 // because termination signals never originate in that way. |
| 256 int rv = raise(sig); |
| 257 DPLOG_IF(ERROR, rv != 0) << "raise"; |
| 258 ALLOW_UNUSED_LOCAL(rv); |
| 259 } |
| 260 |
201 void InstallCrashHandler() { | 261 void InstallCrashHandler() { |
202 struct sigaction sa = {}; | |
203 sigemptyset(&sa.sa_mask); | |
204 sa.sa_flags = SA_SIGINFO; | |
205 sa.sa_sigaction = HandleCrashSignal; | |
206 | |
207 // These are the core-generating signals from 10.12.3 | 262 // These are the core-generating signals from 10.12.3 |
208 // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the | 263 // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the |
209 // set. | 264 // set. |
210 const int kSignals[] = {SIGQUIT, | 265 const int kCrashSignals[] = {SIGQUIT, |
211 SIGILL, | 266 SIGILL, |
212 SIGTRAP, | 267 SIGTRAP, |
213 SIGABRT, | 268 SIGABRT, |
214 SIGEMT, | 269 SIGEMT, |
215 SIGFPE, | 270 SIGFPE, |
216 SIGBUS, | 271 SIGBUS, |
217 SIGSEGV, | 272 SIGSEGV, |
218 SIGSYS}; | 273 SIGSYS}; |
| 274 InstallSignalHandler( |
| 275 std::vector<int>(&kCrashSignals[0], |
| 276 &kCrashSignals[arraysize(kCrashSignals)]), |
| 277 HandleCrashSignal); |
219 | 278 |
220 for (int sig : kSignals) { | 279 // Not a crash handler, but close enough. These are non-core-generating but |
221 DCHECK_GT(sig, 0); | 280 // terminating signals from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop: |
222 DCHECK_LT(static_cast<size_t>(sig), arraysize(g_original_crash_sigaction)); | 281 // entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded |
223 int rv = sigaction(sig, &sa, &g_original_crash_sigaction[sig]); | 282 // because it is uncatchable. |
224 PCHECK(rv == 0) << "sigaction " << sig; | 283 const int kTerminateSignals[] = {SIGHUP, |
225 } | 284 SIGINT, |
| 285 SIGPIPE, |
| 286 SIGALRM, |
| 287 SIGTERM, |
| 288 SIGXCPU, |
| 289 SIGXFSZ, |
| 290 SIGVTALRM, |
| 291 SIGPROF, |
| 292 SIGUSR1, |
| 293 SIGUSR2}; |
| 294 InstallSignalHandler( |
| 295 std::vector<int>(&kTerminateSignals[0], |
| 296 &kTerminateSignals[arraysize(kTerminateSignals)]), |
| 297 HandleTerminateSignal); |
226 } | 298 } |
227 | 299 |
228 struct ResetSIGTERMTraits { | 300 struct ResetSIGTERMTraits { |
229 static struct sigaction* InvalidValue() { | 301 static struct sigaction* InvalidValue() { |
230 return nullptr; | 302 return nullptr; |
231 } | 303 } |
232 | 304 |
233 static void Free(struct sigaction* sa) { | 305 static void Free(struct sigaction* sa) { |
234 int rv = sigaction(SIGTERM, sa, nullptr); | 306 int rv = sigaction(SIGTERM, sa, nullptr); |
235 PLOG_IF(ERROR, rv != 0) << "sigaction"; | 307 PLOG_IF(ERROR, rv != 0) << "sigaction"; |
236 } | 308 } |
237 }; | 309 }; |
238 using ScopedResetSIGTERM = | 310 using ScopedResetSIGTERM = |
239 base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>; | 311 base::ScopedGeneric<struct sigaction*, ResetSIGTERMTraits>; |
240 | 312 |
241 ExceptionHandlerServer* g_exception_handler_server; | 313 ExceptionHandlerServer* g_exception_handler_server; |
242 | 314 |
243 // This signal handler is only operative when being run from launchd. | 315 // This signal handler is only operative when being run from launchd. |
244 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { | 316 void HandleSIGTERM(int sig, siginfo_t* siginfo, void* context) { |
| 317 // Don’t call MetricsRecordExit(). This is part of the normal exit path when |
| 318 // running from launchd. |
| 319 |
245 DCHECK(g_exception_handler_server); | 320 DCHECK(g_exception_handler_server); |
246 g_exception_handler_server->Stop(); | 321 g_exception_handler_server->Stop(); |
247 } | 322 } |
248 | 323 |
249 #elif defined(OS_WIN) | 324 #elif defined(OS_WIN) |
250 | 325 |
251 LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; | 326 LONG(WINAPI* g_original_exception_filter)(EXCEPTION_POINTERS*) = nullptr; |
252 | 327 |
253 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 328 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
| 329 MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed); |
254 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); | 330 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); |
255 | 331 |
256 if (g_original_exception_filter) | 332 if (g_original_exception_filter) |
257 return g_original_exception_filter(exception_pointers); | 333 return g_original_exception_filter(exception_pointers); |
258 else | 334 else |
259 return EXCEPTION_CONTINUE_SEARCH; | 335 return EXCEPTION_CONTINUE_SEARCH; |
260 } | 336 } |
261 | 337 |
| 338 // Handles events like Control-C and Control-Break on a console. |
| 339 BOOL WINAPI ConsoleHandler(DWORD console_event) { |
| 340 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
| 341 return false; |
| 342 } |
| 343 |
| 344 // Handles a WM_ENDSESSION message sent when the user session is ending. |
| 345 class TerminateHandler final : public SessionEndWatcher { |
| 346 public: |
| 347 TerminateHandler() : SessionEndWatcher() {} |
| 348 ~TerminateHandler() override {} |
| 349 |
| 350 private: |
| 351 // SessionEndWatcher: |
| 352 void SessionEnding() override { |
| 353 MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated); |
| 354 } |
| 355 |
| 356 DISALLOW_COPY_AND_ASSIGN(TerminateHandler); |
| 357 }; |
| 358 |
262 void InstallCrashHandler() { | 359 void InstallCrashHandler() { |
263 g_original_exception_filter = | 360 g_original_exception_filter = |
264 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 361 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
| 362 |
| 363 // These are termination handlers, not crash handlers, but that’s close |
| 364 // enough. Note that destroying the TerminateHandler would wait for its thread |
| 365 // to exit, which isn’t necessary or desirable. |
| 366 SetConsoleCtrlHandler(ConsoleHandler, true); |
| 367 static TerminateHandler* terminate_handler = new TerminateHandler(); |
| 368 ALLOW_UNUSED_LOCAL(terminate_handler); |
265 } | 369 } |
266 | 370 |
267 #endif // OS_MACOSX | 371 #endif // OS_MACOSX |
268 | 372 |
269 } // namespace | 373 } // namespace |
270 | 374 |
271 int HandlerMain(int argc, char* argv[]) { | 375 int HandlerMain(int argc, char* argv[]) { |
272 InstallCrashHandler(); | 376 InstallCrashHandler(); |
| 377 CallMetricsRecordNormalExit metrics_record_normal_exit; |
273 | 378 |
274 const base::FilePath argv0( | 379 const base::FilePath argv0( |
275 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); | 380 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); |
276 const base::FilePath me(argv0.BaseName()); | 381 const base::FilePath me(argv0.BaseName()); |
277 | 382 |
278 enum OptionFlags { | 383 enum OptionFlags { |
279 // Long options without short equivalents. | 384 // Long options without short equivalents. |
280 kOptionLastChar = 255, | 385 kOptionLastChar = 255, |
281 kOptionAnnotation, | 386 kOptionAnnotation, |
282 kOptionDatabase, | 387 kOptionDatabase, |
283 #if defined(OS_MACOSX) | 388 #if defined(OS_MACOSX) |
284 kOptionHandshakeFD, | 389 kOptionHandshakeFD, |
285 #endif // OS_MACOSX | 390 #endif // OS_MACOSX |
286 #if defined(OS_WIN) | 391 #if defined(OS_WIN) |
287 kOptionInitialClientData, | 392 kOptionInitialClientData, |
288 #endif // OS_WIN | 393 #endif // OS_WIN |
289 #if defined(OS_MACOSX) | 394 #if defined(OS_MACOSX) |
290 kOptionMachService, | 395 kOptionMachService, |
291 #endif // OS_MACOSX | 396 #endif // OS_MACOSX |
292 kOptionMetrics, | 397 kOptionMetrics, |
293 kOptionNoRateLimit, | 398 kOptionNoRateLimit, |
| 399 kOptionNoUploadGzip, |
294 #if defined(OS_MACOSX) | 400 #if defined(OS_MACOSX) |
295 kOptionResetOwnCrashExceptionPortToSystemDefault, | 401 kOptionResetOwnCrashExceptionPortToSystemDefault, |
296 #elif defined(OS_WIN) | 402 #elif defined(OS_WIN) |
297 kOptionPipeName, | 403 kOptionPipeName, |
298 #endif // OS_MACOSX | 404 #endif // OS_MACOSX |
299 kOptionURL, | 405 kOptionURL, |
300 | 406 |
301 // Standard options. | 407 // Standard options. |
302 kOptionHelp = -2, | 408 kOptionHelp = -2, |
303 kOptionVersion = -3, | 409 kOptionVersion = -3, |
304 }; | 410 }; |
305 | 411 |
306 struct { | 412 struct { |
307 std::map<std::string, std::string> annotations; | 413 std::map<std::string, std::string> annotations; |
308 std::string url; | 414 std::string url; |
309 const char* database; | 415 const char* database; |
310 const char* metrics; | 416 const char* metrics; |
311 #if defined(OS_MACOSX) | 417 #if defined(OS_MACOSX) |
312 int handshake_fd; | 418 int handshake_fd; |
313 std::string mach_service; | 419 std::string mach_service; |
314 bool reset_own_crash_exception_port_to_system_default; | 420 bool reset_own_crash_exception_port_to_system_default; |
315 #elif defined(OS_WIN) | 421 #elif defined(OS_WIN) |
316 std::string pipe_name; | 422 std::string pipe_name; |
317 InitialClientData initial_client_data; | 423 InitialClientData initial_client_data; |
318 #endif // OS_MACOSX | 424 #endif // OS_MACOSX |
319 bool rate_limit; | 425 bool rate_limit; |
| 426 bool upload_gzip; |
320 } options = {}; | 427 } options = {}; |
321 #if defined(OS_MACOSX) | 428 #if defined(OS_MACOSX) |
322 options.handshake_fd = -1; | 429 options.handshake_fd = -1; |
323 #endif | 430 #endif |
324 options.rate_limit = true; | 431 options.rate_limit = true; |
| 432 options.upload_gzip = true; |
325 | 433 |
326 const option long_options[] = { | 434 const option long_options[] = { |
327 {"annotation", required_argument, nullptr, kOptionAnnotation}, | 435 {"annotation", required_argument, nullptr, kOptionAnnotation}, |
328 {"database", required_argument, nullptr, kOptionDatabase}, | 436 {"database", required_argument, nullptr, kOptionDatabase}, |
329 #if defined(OS_MACOSX) | 437 #if defined(OS_MACOSX) |
330 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, | 438 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, |
331 #endif // OS_MACOSX | 439 #endif // OS_MACOSX |
332 #if defined(OS_WIN) | 440 #if defined(OS_WIN) |
333 {"initial-client-data", | 441 {"initial-client-data", |
334 required_argument, | 442 required_argument, |
335 nullptr, | 443 nullptr, |
336 kOptionInitialClientData}, | 444 kOptionInitialClientData}, |
337 #endif // OS_MACOSX | 445 #endif // OS_MACOSX |
338 #if defined(OS_MACOSX) | 446 #if defined(OS_MACOSX) |
339 {"mach-service", required_argument, nullptr, kOptionMachService}, | 447 {"mach-service", required_argument, nullptr, kOptionMachService}, |
340 #endif // OS_MACOSX | 448 #endif // OS_MACOSX |
341 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, | 449 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, |
342 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, | 450 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, |
| 451 {"no-upload-gzip", no_argument, nullptr, kOptionNoUploadGzip}, |
343 #if defined(OS_MACOSX) | 452 #if defined(OS_MACOSX) |
344 {"reset-own-crash-exception-port-to-system-default", | 453 {"reset-own-crash-exception-port-to-system-default", |
345 no_argument, | 454 no_argument, |
346 nullptr, | 455 nullptr, |
347 kOptionResetOwnCrashExceptionPortToSystemDefault}, | 456 kOptionResetOwnCrashExceptionPortToSystemDefault}, |
348 #elif defined(OS_WIN) | 457 #elif defined(OS_WIN) |
349 {"pipe-name", required_argument, nullptr, kOptionPipeName}, | 458 {"pipe-name", required_argument, nullptr, kOptionPipeName}, |
350 #endif // OS_MACOSX | 459 #endif // OS_MACOSX |
351 {"url", required_argument, nullptr, kOptionURL}, | 460 {"url", required_argument, nullptr, kOptionURL}, |
352 {"help", no_argument, nullptr, kOptionHelp}, | 461 {"help", no_argument, nullptr, kOptionHelp}, |
353 {"version", no_argument, nullptr, kOptionVersion}, | 462 {"version", no_argument, nullptr, kOptionVersion}, |
354 {nullptr, 0, nullptr, 0}, | 463 {nullptr, 0, nullptr, 0}, |
355 }; | 464 }; |
356 | 465 |
357 int opt; | 466 int opt; |
358 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { | 467 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { |
359 switch (opt) { | 468 switch (opt) { |
360 case kOptionAnnotation: { | 469 case kOptionAnnotation: { |
361 std::string key; | 470 std::string key; |
362 std::string value; | 471 std::string value; |
363 if (!SplitStringFirst(optarg, '=', &key, &value)) { | 472 if (!SplitStringFirst(optarg, '=', &key, &value)) { |
364 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); | 473 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); |
365 return EXIT_FAILURE; | 474 return ExitFailure(); |
366 } | 475 } |
367 std::string old_value; | 476 std::string old_value; |
368 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { | 477 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { |
369 LOG(WARNING) << "duplicate key " << key << ", discarding value " | 478 LOG(WARNING) << "duplicate key " << key << ", discarding value " |
370 << old_value; | 479 << old_value; |
371 } | 480 } |
372 break; | 481 break; |
373 } | 482 } |
374 case kOptionDatabase: { | 483 case kOptionDatabase: { |
375 options.database = optarg; | 484 options.database = optarg; |
376 break; | 485 break; |
377 } | 486 } |
378 #if defined(OS_MACOSX) | 487 #if defined(OS_MACOSX) |
379 case kOptionHandshakeFD: { | 488 case kOptionHandshakeFD: { |
380 if (!StringToNumber(optarg, &options.handshake_fd) || | 489 if (!StringToNumber(optarg, &options.handshake_fd) || |
381 options.handshake_fd < 0) { | 490 options.handshake_fd < 0) { |
382 ToolSupport::UsageHint(me, | 491 ToolSupport::UsageHint(me, |
383 "--handshake-fd requires a file descriptor"); | 492 "--handshake-fd requires a file descriptor"); |
384 return EXIT_FAILURE; | 493 return ExitFailure(); |
385 } | 494 } |
386 break; | 495 break; |
387 } | 496 } |
388 case kOptionMachService: { | 497 case kOptionMachService: { |
389 options.mach_service = optarg; | 498 options.mach_service = optarg; |
390 break; | 499 break; |
391 } | 500 } |
392 #elif defined(OS_WIN) | 501 #elif defined(OS_WIN) |
393 case kOptionInitialClientData: { | 502 case kOptionInitialClientData: { |
394 if (!options.initial_client_data.InitializeFromString(optarg)) { | 503 if (!options.initial_client_data.InitializeFromString(optarg)) { |
395 ToolSupport::UsageHint( | 504 ToolSupport::UsageHint( |
396 me, "failed to parse --initial-client-data"); | 505 me, "failed to parse --initial-client-data"); |
397 return EXIT_FAILURE; | 506 return ExitFailure(); |
398 } | 507 } |
399 break; | 508 break; |
400 } | 509 } |
401 #endif // OS_MACOSX | 510 #endif // OS_MACOSX |
402 case kOptionMetrics: { | 511 case kOptionMetrics: { |
403 options.metrics = optarg; | 512 options.metrics = optarg; |
404 break; | 513 break; |
405 } | 514 } |
406 case kOptionNoRateLimit: { | 515 case kOptionNoRateLimit: { |
407 options.rate_limit = false; | 516 options.rate_limit = false; |
408 break; | 517 break; |
409 } | 518 } |
| 519 case kOptionNoUploadGzip: { |
| 520 options.upload_gzip = false; |
| 521 break; |
| 522 } |
410 #if defined(OS_MACOSX) | 523 #if defined(OS_MACOSX) |
411 case kOptionResetOwnCrashExceptionPortToSystemDefault: { | 524 case kOptionResetOwnCrashExceptionPortToSystemDefault: { |
412 options.reset_own_crash_exception_port_to_system_default = true; | 525 options.reset_own_crash_exception_port_to_system_default = true; |
413 break; | 526 break; |
414 } | 527 } |
415 #elif defined(OS_WIN) | 528 #elif defined(OS_WIN) |
416 case kOptionPipeName: { | 529 case kOptionPipeName: { |
417 options.pipe_name = optarg; | 530 options.pipe_name = optarg; |
418 break; | 531 break; |
419 } | 532 } |
420 #endif // OS_MACOSX | 533 #endif // OS_MACOSX |
421 case kOptionURL: { | 534 case kOptionURL: { |
422 options.url = optarg; | 535 options.url = optarg; |
423 break; | 536 break; |
424 } | 537 } |
425 case kOptionHelp: { | 538 case kOptionHelp: { |
426 Usage(me); | 539 Usage(me); |
| 540 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); |
427 return EXIT_SUCCESS; | 541 return EXIT_SUCCESS; |
428 } | 542 } |
429 case kOptionVersion: { | 543 case kOptionVersion: { |
430 ToolSupport::Version(me); | 544 ToolSupport::Version(me); |
| 545 MetricsRecordExit(Metrics::LifetimeMilestone::kExitedEarly); |
431 return EXIT_SUCCESS; | 546 return EXIT_SUCCESS; |
432 } | 547 } |
433 default: { | 548 default: { |
434 ToolSupport::UsageHint(me, nullptr); | 549 ToolSupport::UsageHint(me, nullptr); |
435 return EXIT_FAILURE; | 550 return ExitFailure(); |
436 } | 551 } |
437 } | 552 } |
438 } | 553 } |
439 argc -= optind; | 554 argc -= optind; |
440 argv += optind; | 555 argv += optind; |
441 | 556 |
442 #if defined(OS_MACOSX) | 557 #if defined(OS_MACOSX) |
443 if (options.handshake_fd < 0 && options.mach_service.empty()) { | 558 if (options.handshake_fd < 0 && options.mach_service.empty()) { |
444 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); | 559 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); |
445 return EXIT_FAILURE; | 560 return ExitFailure(); |
446 } | 561 } |
447 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { | 562 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { |
448 ToolSupport::UsageHint( | 563 ToolSupport::UsageHint( |
449 me, "--handshake-fd and --mach-service are incompatible"); | 564 me, "--handshake-fd and --mach-service are incompatible"); |
450 return EXIT_FAILURE; | 565 return ExitFailure(); |
451 } | 566 } |
452 #elif defined(OS_WIN) | 567 #elif defined(OS_WIN) |
453 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { | 568 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { |
454 ToolSupport::UsageHint(me, | 569 ToolSupport::UsageHint(me, |
455 "--initial-client-data or --pipe-name is required"); | 570 "--initial-client-data or --pipe-name is required"); |
456 return EXIT_FAILURE; | 571 return ExitFailure(); |
457 } | 572 } |
458 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { | 573 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { |
459 ToolSupport::UsageHint( | 574 ToolSupport::UsageHint( |
460 me, "--initial-client-data and --pipe-name are incompatible"); | 575 me, "--initial-client-data and --pipe-name are incompatible"); |
461 return EXIT_FAILURE; | 576 return ExitFailure(); |
462 } | 577 } |
463 #endif // OS_MACOSX | 578 #endif // OS_MACOSX |
464 | 579 |
465 if (!options.database) { | 580 if (!options.database) { |
466 ToolSupport::UsageHint(me, "--database is required"); | 581 ToolSupport::UsageHint(me, "--database is required"); |
467 return EXIT_FAILURE; | 582 return ExitFailure(); |
468 } | 583 } |
469 | 584 |
470 if (argc) { | 585 if (argc) { |
471 ToolSupport::UsageHint(me, nullptr); | 586 ToolSupport::UsageHint(me, nullptr); |
472 return EXIT_FAILURE; | 587 return ExitFailure(); |
473 } | 588 } |
474 | 589 |
475 #if defined(OS_MACOSX) | 590 #if defined(OS_MACOSX) |
476 if (options.mach_service.empty()) { | 591 if (options.mach_service.empty()) { |
477 // Don’t do this when being run by launchd. See launchd.plist(5). | 592 // Don’t do this when being run by launchd. See launchd.plist(5). |
478 CloseStdinAndStdout(); | 593 CloseStdinAndStdout(); |
479 } | 594 } |
480 | 595 |
481 if (options.reset_own_crash_exception_port_to_system_default) { | 596 if (options.reset_own_crash_exception_port_to_system_default) { |
482 CrashpadClient::UseSystemDefaultHandler(); | 597 CrashpadClient::UseSystemDefaultHandler(); |
483 } | 598 } |
484 | 599 |
485 base::mac::ScopedMachReceiveRight receive_right; | 600 base::mac::ScopedMachReceiveRight receive_right; |
486 | 601 |
487 if (options.handshake_fd >= 0) { | 602 if (options.handshake_fd >= 0) { |
488 receive_right.reset( | 603 receive_right.reset( |
489 ChildPortHandshake::RunServerForFD( | 604 ChildPortHandshake::RunServerForFD( |
490 base::ScopedFD(options.handshake_fd), | 605 base::ScopedFD(options.handshake_fd), |
491 ChildPortHandshake::PortRightType::kReceiveRight)); | 606 ChildPortHandshake::PortRightType::kReceiveRight)); |
492 } else if (!options.mach_service.empty()) { | 607 } else if (!options.mach_service.empty()) { |
493 receive_right = BootstrapCheckIn(options.mach_service); | 608 receive_right = BootstrapCheckIn(options.mach_service); |
494 } | 609 } |
495 | 610 |
496 if (!receive_right.is_valid()) { | 611 if (!receive_right.is_valid()) { |
497 return EXIT_FAILURE; | 612 return ExitFailure(); |
498 } | 613 } |
499 | 614 |
500 ExceptionHandlerServer exception_handler_server( | 615 ExceptionHandlerServer exception_handler_server( |
501 std::move(receive_right), !options.mach_service.empty()); | 616 std::move(receive_right), !options.mach_service.empty()); |
502 base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server( | 617 base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server( |
503 &g_exception_handler_server, &exception_handler_server); | 618 &g_exception_handler_server, &exception_handler_server); |
504 | 619 |
505 struct sigaction old_sa; | 620 struct sigaction old_sa; |
506 ScopedResetSIGTERM reset_sigterm; | 621 ScopedResetSIGTERM reset_sigterm; |
507 if (!options.mach_service.empty()) { | 622 if (!options.mach_service.empty()) { |
508 // When running from launchd, no no-senders notification could ever be | 623 // When running from launchd, no no-senders notification could ever be |
509 // triggered, because launchd maintains a send right to the service. When | 624 // triggered, because launchd maintains a send right to the service. When |
510 // launchd wants the job to exit, it will send a SIGTERM. See | 625 // launchd wants the job to exit, it will send a SIGTERM. See |
511 // launchd.plist(5). | 626 // launchd.plist(5). |
512 // | 627 // |
513 // Set up a SIGTERM handler that will call exception_handler_server.Stop(). | 628 // Set up a SIGTERM handler that will call exception_handler_server.Stop(). |
| 629 // This replaces the HandleTerminateSignal handler for SIGTERM. |
514 struct sigaction sa = {}; | 630 struct sigaction sa = {}; |
515 sigemptyset(&sa.sa_mask); | 631 sigemptyset(&sa.sa_mask); |
516 sa.sa_flags = SA_SIGINFO; | 632 sa.sa_flags = SA_SIGINFO; |
517 sa.sa_sigaction = HandleSIGTERM; | 633 sa.sa_sigaction = HandleSIGTERM; |
518 int rv = sigaction(SIGTERM, &sa, &old_sa); | 634 int rv = sigaction(SIGTERM, &sa, &old_sa); |
519 PCHECK(rv == 0) << "sigaction"; | 635 PCHECK(rv == 0) << "sigaction"; |
520 reset_sigterm.reset(&old_sa); | 636 reset_sigterm.reset(&old_sa); |
521 } | 637 } |
522 #elif defined(OS_WIN) | 638 #elif defined(OS_WIN) |
523 // Shut down as late as possible relative to programs we're watching. | 639 // Shut down as late as possible relative to programs we're watching. |
(...skipping 13 matching lines...) Expand all Loading... |
537 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); | 653 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); |
538 static const char kMetricsName[] = "CrashpadMetrics"; | 654 static const char kMetricsName[] = "CrashpadMetrics"; |
539 const size_t kMetricsFileSize = 1 << 20; | 655 const size_t kMetricsFileSize = 1 << 20; |
540 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( | 656 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( |
541 metrics_dir, kMetricsFileSize, 0, kMetricsName)) { | 657 metrics_dir, kMetricsFileSize, 0, kMetricsName)) { |
542 histogram_allocator = base::GlobalHistogramAllocator::Get(); | 658 histogram_allocator = base::GlobalHistogramAllocator::Get(); |
543 histogram_allocator->CreateTrackingHistograms(kMetricsName); | 659 histogram_allocator->CreateTrackingHistograms(kMetricsName); |
544 } | 660 } |
545 } | 661 } |
546 | 662 |
| 663 Metrics::HandlerLifetimeMilestone(Metrics::LifetimeMilestone::kStarted); |
| 664 |
547 std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize( | 665 std::unique_ptr<CrashReportDatabase> database(CrashReportDatabase::Initialize( |
548 base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType( | 666 base::FilePath(ToolSupport::CommandLineArgumentToFilePathStringType( |
549 options.database)))); | 667 options.database)))); |
550 if (!database) { | 668 if (!database) { |
551 return EXIT_FAILURE; | 669 return ExitFailure(); |
552 } | 670 } |
553 | 671 |
554 // TODO(scottmg): options.rate_limit should be removed when we have a | 672 // TODO(scottmg): options.rate_limit should be removed when we have a |
555 // configurable database setting to control upload limiting. | 673 // configurable database setting to control upload limiting. |
556 // See https://crashpad.chromium.org/bug/23. | 674 // See https://crashpad.chromium.org/bug/23. |
557 CrashReportUploadThread upload_thread( | 675 CrashReportUploadThread upload_thread( |
558 database.get(), options.url, options.rate_limit); | 676 database.get(), options.url, options.rate_limit, options.upload_gzip); |
559 upload_thread.Start(); | 677 upload_thread.Start(); |
560 | 678 |
561 PruneCrashReportThread prune_thread(database.get(), | 679 PruneCrashReportThread prune_thread(database.get(), |
562 PruneCondition::GetDefault()); | 680 PruneCondition::GetDefault()); |
563 prune_thread.Start(); | 681 prune_thread.Start(); |
564 | 682 |
565 CrashReportExceptionHandler exception_handler( | 683 CrashReportExceptionHandler exception_handler( |
566 database.get(), &upload_thread, &options.annotations); | 684 database.get(), &upload_thread, &options.annotations); |
567 | 685 |
568 #if defined(OS_WIN) | 686 #if defined(OS_WIN) |
569 if (options.initial_client_data.IsValid()) { | 687 if (options.initial_client_data.IsValid()) { |
570 exception_handler_server.InitializeWithInheritedDataForInitialClient( | 688 exception_handler_server.InitializeWithInheritedDataForInitialClient( |
571 options.initial_client_data, &exception_handler); | 689 options.initial_client_data, &exception_handler); |
572 } | 690 } |
573 #endif // OS_WIN | 691 #endif // OS_WIN |
574 | 692 |
575 exception_handler_server.Run(&exception_handler); | 693 exception_handler_server.Run(&exception_handler); |
576 | 694 |
577 upload_thread.Stop(); | 695 upload_thread.Stop(); |
578 prune_thread.Stop(); | 696 prune_thread.Stop(); |
579 | 697 |
580 if (histogram_allocator) | 698 if (histogram_allocator) |
581 histogram_allocator->DeletePersistentLocation(); | 699 histogram_allocator->DeletePersistentLocation(); |
582 | 700 |
583 return EXIT_SUCCESS; | 701 return EXIT_SUCCESS; |
584 } | 702 } |
585 | 703 |
586 } // namespace crashpad | 704 } // namespace crashpad |
OLD | NEW |