Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: shell/crash/breakpad.cc

Issue 1227333002: Add breakpad support to mojo shell apk. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Follow review Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // This file was forked from components/crash/app/breakpad_linux.cc and
6 // components/crash/app/breakpad_linux_impl.h in chromium.
7
8 // For linux_syscall_support.h. This makes it safe to call embedded system
9 // calls when in seccomp mode.
10
11 #include "shell/crash/breakpad.h"
12
13 #include <fcntl.h>
14 #include <poll.h>
15 #include <signal.h>
16 #include <stdlib.h>
17 #include <sys/socket.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <sys/uio.h>
21 #include <sys/wait.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include <algorithm>
26 #include <string>
27
28 #include "base/command_line.h"
29 #include "base/debug/crash_logging.h"
30 #include "base/debug/dump_without_crashing.h"
31 #include "base/files/file_path.h"
32 #include "base/files/file_util.h"
33 #include "base/linux_util.h"
34 #include "base/macros.h"
35 #include "base/path_service.h"
36 #include "base/posix/eintr_wrapper.h"
37 #include "base/process/memory.h"
38 #include "base/strings/string_util.h"
39 #include "build/build_config.h"
40 #include "third_party/breakpad/src/client/linux/crash_generation/crash_generatio n_client.h"
41 #include "third_party/breakpad/src/client/linux/handler/exception_handler.h"
42 #include "third_party/breakpad/src/client/linux/minidump_writer/directory_reader .h"
43 #include "third_party/breakpad/src/common/linux/linux_libc_support.h"
44 #include "third_party/breakpad/src/common/memory.h"
45 #include "third_party/breakpad/src/common/simple_string_dictionary.h"
46
47 #if defined(OS_ANDROID)
48 #include <android/log.h>
49 #include <sys/stat.h>
50
51 #include "base/android/build_info.h"
52 #include "base/android/path_utils.h"
53 #endif
54 #include "third_party/lss/linux_syscall_support.h"
55
56 #if defined(OS_ANDROID)
57 #define STAT_STRUCT struct stat
58 #define FSTAT_FUNC fstat
59 #else
60 #define STAT_STRUCT struct kernel_stat
61 #define FSTAT_FUNC sys_fstat
62 #endif
63
64 // Some versions of gcc are prone to warn about unused return values. In cases
65 // where we either a) know the call cannot fail, or b) there is nothing we
66 // can do when a call fails, we mark the return code as ignored. This avoids
67 // spurious compiler warnings.
68 #define IGNORE_RET(x) \
69 do { \
70 if (x) \
71 ; \
72 } while (0)
73
74 using google_breakpad::ExceptionHandler;
75 using google_breakpad::MinidumpDescriptor;
76
77 namespace breakpad {
78
79 namespace {
80
81 using CrashKeyStorage = google_breakpad::NonAllocatingMap<256, 256, 64>;
82
83 // BreakpadInfo describes a crash report.
84 // The minidump information can either be contained in a file descriptor (fd) or
85 // in a file (whose path is in filename).
86 struct BreakpadInfo {
87 int fd; // File descriptor to the Breakpad dump data.
88 const char* filename; // Path to the Breakpad dump data.
89 const char* process_type; // Process type, e.g. "renderer".
90 unsigned process_type_length; // Length of |process_type|.
91 const char* distro; // Linux distro string.
92 unsigned distro_length; // Length of |distro|.
93 uint64_t process_start_time; // Uptime of the crashing process.
94 size_t oom_size; // Amount of memory requested if OOM.
95 uint64_t pid; // PID where applicable.
96 CrashKeyStorage* crash_keys;
97 };
98
99 // Define a preferred limit on minidump sizes, because Crash Server currently
100 // throws away any larger than 1.2MB (1.2 * 1024 * 1024). A value of -1 means
101 // no limit.
102 static const off_t kMaxMinidumpFileSize = 1258291;
103 bool g_is_crash_reporter_enabled = false;
104 uint64_t g_process_start_time = 0;
105 pid_t g_pid = 0;
106 ExceptionHandler* g_breakpad = nullptr;
107
108 CrashKeyStorage* g_crash_keys = nullptr;
109
110 #if defined(OS_ANDROID)
111 const char kProductName[] = "Mojo_Android";
112 #else
113 const char kProductName[] = "Mojo";
114 #endif
115 const char kVersion[] = "1.0.0";
116
117 // Writes the value |v| as 16 hex characters to the memory pointed at by
118 // |output|.
119 void write_uint64_hex(char* output, uint64_t v) {
120 static const char hextable[] = "0123456789abcdef";
121
122 for (int i = 15; i >= 0; --i) {
123 output[i] = hextable[v & 15];
124 v >>= 4;
125 }
126 }
127
128 // The following helper functions are for calculating uptime.
129
130 // Converts a struct timeval to milliseconds.
131 uint64_t timeval_to_ms(struct timeval* tv) {
132 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
133 ret *= 1000;
134 ret += tv->tv_usec / 1000;
135 return ret;
136 }
137
138 // Converts a struct timeval to milliseconds.
139 uint64_t kernel_timeval_to_ms(struct kernel_timeval* tv) {
140 uint64_t ret = tv->tv_sec; // Avoid overflow by explicitly using a uint64_t.
141 ret *= 1000;
142 ret += tv->tv_usec / 1000;
143 return ret;
144 }
145
146 // String buffer size to use to convert a uint64_t to string.
147 const size_t kUint64StringSize = 21;
148
149 void SetProcessStartTime() {
150 // Set the base process start time value.
151 struct timeval tv;
152 if (!gettimeofday(&tv, nullptr))
153 g_process_start_time = timeval_to_ms(&tv);
154 else
155 g_process_start_time = 0;
156 }
157
158 // uint64_t version of my_int_len() from
159 // breakpad/src/common/linux/linux_libc_support.h. Return the length of the
160 // given, non-negative integer when expressed in base 10.
161 unsigned my_uint64_len(uint64_t i) {
162 if (!i)
163 return 1;
164
165 unsigned len = 0;
166 while (i) {
167 len++;
168 i /= 10;
169 }
170
171 return len;
172 }
173
174 // uint64_t version of my_uitos() from
175 // breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
176 // integer to a string (not null-terminated).
177 void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
178 for (unsigned index = i_len; index; --index, i /= 10)
179 output[index - 1] = '0' + (i % 10);
180 }
181
182 size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
183 while (len > 0 && str[len - 1] == ' ') {
184 len--;
185 }
186 return len;
187 }
188
189 // MIME substrings.
190 const char g_rn[] = "\r\n";
191 const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
192 const char g_quote_msg[] = "\"";
193 const char g_dashdash_msg[] = "--";
194 const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
195 const char g_content_type_msg[] = "Content-Type: application/octet-stream";
196
197 // MimeWriter manages an iovec for writing MIMEs to a file.
198 class MimeWriter {
199 public:
200 static const int kIovCapacity = 30;
201 static const size_t kMaxCrashChunkSize = 64;
202
203 MimeWriter(int fd, const char* const mime_boundary);
204 ~MimeWriter();
205
206 // Append boundary.
207 virtual void AddBoundary();
208
209 // Append end of file boundary.
210 virtual void AddEnd();
211
212 // Append key/value pair with specified sizes.
213 virtual void AddPairData(const char* msg_type,
214 size_t msg_type_size,
215 const char* msg_data,
216 size_t msg_data_size);
217
218 // Append key/value pair.
219 void AddPairString(const char* msg_type, const char* msg_data) {
220 AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
221 }
222
223 // Append key/value pair, splitting value into chunks no larger than
224 // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
225 // The msg_type string will have a counter suffix to distinguish each chunk.
226 virtual void AddPairDataInChunks(const char* msg_type,
227 size_t msg_type_size,
228 const char* msg_data,
229 size_t msg_data_size,
230 size_t chunk_size,
231 bool strip_trailing_spaces);
232
233 // Add binary file contents to be uploaded with the specified filename.
234 virtual void AddFileContents(const char* filename_msg,
235 uint8_t* file_data,
236 size_t file_size);
237
238 // Flush any pending iovecs to the output file.
239 void Flush() {
240 IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
241 iov_index_ = 0;
242 }
243
244 protected:
245 void AddItem(const void* base, size_t size);
246 // Minor performance trade-off for easier-to-maintain code.
247 void AddString(const char* str) { AddItem(str, my_strlen(str)); }
248 void AddItemWithoutTrailingSpaces(const void* base, size_t size);
249
250 struct kernel_iovec iov_[kIovCapacity];
251 int iov_index_;
252
253 // Output file descriptor.
254 int fd_;
255
256 const char* const mime_boundary_;
257
258 private:
259 DISALLOW_COPY_AND_ASSIGN(MimeWriter);
260 };
261
262 MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
263 : iov_index_(0), fd_(fd), mime_boundary_(mime_boundary) {
264 }
265
266 MimeWriter::~MimeWriter() {
267 }
268
269 void MimeWriter::AddBoundary() {
270 AddString(mime_boundary_);
271 AddString(g_rn);
272 }
273
274 void MimeWriter::AddEnd() {
275 AddString(mime_boundary_);
276 AddString(g_dashdash_msg);
277 AddString(g_rn);
278 }
279
280 void MimeWriter::AddPairData(const char* msg_type,
281 size_t msg_type_size,
282 const char* msg_data,
283 size_t msg_data_size) {
284 AddString(g_form_data_msg);
285 AddItem(msg_type, msg_type_size);
286 AddString(g_quote_msg);
287 AddString(g_rn);
288 AddString(g_rn);
289 AddItem(msg_data, msg_data_size);
290 AddString(g_rn);
291 }
292
293 void MimeWriter::AddPairDataInChunks(const char* msg_type,
294 size_t msg_type_size,
295 const char* msg_data,
296 size_t msg_data_size,
297 size_t chunk_size,
298 bool strip_trailing_spaces) {
299 if (chunk_size > kMaxCrashChunkSize)
300 return;
301
302 unsigned i = 0;
303 size_t done = 0, msg_length = msg_data_size;
304
305 while (msg_length) {
306 char num[kUint64StringSize];
307 const unsigned num_len = my_uint_len(++i);
308 my_uitos(num, i, num_len);
309
310 size_t chunk_len = std::min(chunk_size, msg_length);
311
312 AddString(g_form_data_msg);
313 AddItem(msg_type, msg_type_size);
314 AddItem(num, num_len);
315 AddString(g_quote_msg);
316 AddString(g_rn);
317 AddString(g_rn);
318 if (strip_trailing_spaces) {
319 AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
320 } else {
321 AddItem(msg_data + done, chunk_len);
322 }
323 AddString(g_rn);
324 AddBoundary();
325 Flush();
326
327 done += chunk_len;
328 msg_length -= chunk_len;
329 }
330 }
331
332 void MimeWriter::AddFileContents(const char* filename_msg,
333 uint8_t* file_data,
334 size_t file_size) {
335 AddString(g_form_data_msg);
336 AddString(filename_msg);
337 AddString(g_rn);
338 AddString(g_content_type_msg);
339 AddString(g_rn);
340 AddString(g_rn);
341 AddItem(file_data, file_size);
342 AddString(g_rn);
343 }
344
345 void MimeWriter::AddItem(const void* base, size_t size) {
346 // Check if the iovec is full and needs to be flushed to output file.
347 if (iov_index_ == kIovCapacity) {
348 Flush();
349 }
350 iov_[iov_index_].iov_base = const_cast<void*>(base);
351 iov_[iov_index_].iov_len = size;
352 ++iov_index_;
353 }
354
355 void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
356 AddItem(base,
357 LengthWithoutTrailingSpaces(static_cast<const char*>(base), size));
358 }
359
360 void DumpProcess() {
361 if (g_breakpad)
362 g_breakpad->WriteMinidump();
363 }
364
365 #if defined(OS_ANDROID)
366 const char kGoogleBreakpad[] = "google-breakpad";
367 #endif
368
369 size_t WriteLog(const char* buf, size_t nbytes) {
370 #if defined(OS_ANDROID)
371 return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
372 #else
373 return sys_write(2, buf, nbytes);
374 #endif
375 }
376
377 #if defined(OS_ANDROID)
378 void AndroidLogWriteHorizontalRule() {
379 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
380 "### ### ### ### ### ### ### ### ### ### ### ### ###");
381 }
382
383 // Android's native crash handler outputs a diagnostic tombstone to the device
384 // log. By returning false from the HandlerCallbacks, breakpad will reinstall
385 // the previous (i.e. native) signal handlers before returning from its own
386 // handler. A Mojo shell build fingerprint is written to the log, so that the
387 // specific build of the shell and the location of the archived shell symbols
388 // can be determined directly from it.
389 bool FinalizeCrashDoneAndroid() {
390 base::android::BuildInfo* android_build_info =
391 base::android::BuildInfo::GetInstance();
392
393 AndroidLogWriteHorizontalRule();
394 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
395 "Mojo shell build fingerprint:");
396 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
397 android_build_info->package_version_name());
398 __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
399 android_build_info->package_version_code());
400 AndroidLogWriteHorizontalRule();
401
402 return false;
403 }
404 #endif
405
406 void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
407 int fd,
408 bool close_fd,
409 uint8_t** file_data,
410 size_t* size) {
411 STAT_STRUCT st;
412 if (FSTAT_FUNC(fd, &st) != 0) {
413 static const char msg[] = "Cannot upload crash dump: stat failed\n";
414 WriteLog(msg, sizeof(msg) - 1);
415 if (close_fd)
416 IGNORE_RET(sys_close(fd));
417 return;
418 }
419
420 *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
421 if (!(*file_data)) {
422 static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
423 WriteLog(msg, sizeof(msg) - 1);
424 if (close_fd)
425 IGNORE_RET(sys_close(fd));
426 return;
427 }
428 my_memset(*file_data, 0xf, st.st_size);
429
430 *size = st.st_size;
431 int byte_read = sys_read(fd, *file_data, *size);
432 if (byte_read == -1) {
433 static const char msg[] = "Cannot upload crash dump: read failed\n";
434 WriteLog(msg, sizeof(msg) - 1);
435 if (close_fd)
436 IGNORE_RET(sys_close(fd));
437 return;
438 }
439
440 if (close_fd)
441 IGNORE_RET(sys_close(fd));
442 }
443
444 void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
445 const char* filename,
446 int* fd,
447 uint8_t** file_data,
448 size_t* size) {
449 // WARNING: this code runs in a compromised context. It may not call into
450 // libc nor allocate memory normally.
451 *fd = sys_open(filename, O_RDONLY, 0);
452 *size = 0;
453
454 if (*fd < 0) {
455 static const char msg[] = "Cannot upload crash dump: failed to open\n";
456 WriteLog(msg, sizeof(msg) - 1);
457 return;
458 }
459
460 LoadDataFromFD(allocator, *fd, true, file_data, size);
461 }
462
463 void HandleCrashDump(const BreakpadInfo& info) {
464 int dumpfd;
465 bool keep_fd = false;
466 size_t dump_size;
467 uint8_t* dump_data;
468 google_breakpad::PageAllocator allocator;
469
470 if (info.fd != -1) {
471 // Dump is provided with an open FD.
472 keep_fd = true;
473 dumpfd = info.fd;
474
475 // The FD is pointing to the end of the file.
476 // Rewind, we'll read the data next.
477 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
478 static const char msg[] =
479 "Cannot upload crash dump: failed to "
480 "reposition minidump FD\n";
481 WriteLog(msg, sizeof(msg) - 1);
482 IGNORE_RET(sys_close(dumpfd));
483 return;
484 }
485 LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
486 } else {
487 // Dump is provided with a path.
488 keep_fd = false;
489 LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
490 }
491
492 // We need to build a MIME block for uploading to the server. Since we are
493 // going to fork and run wget, it needs to be written to a temp file.
494 const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
495 if (ufd < 0) {
496 static const char msg[] =
497 "Cannot upload crash dump because /dev/urandom"
498 " is missing\n";
499 WriteLog(msg, sizeof(msg) - 1);
500 return;
501 }
502
503 int temp_file_fd = -1;
504 if (keep_fd) {
505 LOG(WARNING) << "Keeping fd...";
506 temp_file_fd = dumpfd;
507 // Rewind the destination, we are going to overwrite it.
508 if (lseek(dumpfd, 0, SEEK_SET) == -1) {
509 static const char msg[] =
510 "Cannot upload crash dump: failed to "
511 "reposition minidump FD (2)\n";
512 WriteLog(msg, sizeof(msg) - 1);
513 IGNORE_RET(sys_close(dumpfd));
514 return;
515 }
516 } else {
517 LOG(WARNING) << "Opening file: " << info.filename;
518 temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
519 if (temp_file_fd < 0) {
520 static const char msg[] = "Failed to save crash dump: failed to open\n";
521 WriteLog(msg, sizeof(msg) - 1);
522 IGNORE_RET(sys_close(ufd));
523 return;
524 }
525 }
526
527 // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
528 char mime_boundary[28 + 16 + 1];
529 my_memset(mime_boundary, '-', 28);
530 uint64_t boundary_rand;
531 sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
532 write_uint64_hex(mime_boundary + 28, boundary_rand);
533 mime_boundary[28 + 16] = 0;
534 IGNORE_RET(sys_close(ufd));
535
536 // The MIME block looks like this:
537 // BOUNDARY \r\n
538 // Content-Disposition: form-data; name="prod" \r\n \r\n
539 // MojoShell \r\n
540 // BOUNDARY \r\n
541 // Content-Disposition: form-data; name="ver" \r\n \r\n
542 // 1.2.3.4 \r\n
543 // BOUNDARY \r\n
544 //
545 // zero or one:
546 // Content-Disposition: form-data; name="ptime" \r\n \r\n
547 // abcdef \r\n
548 // BOUNDARY \r\n
549 //
550 // zero or one:
551 // Content-Disposition: form-data; name="ptype" \r\n \r\n
552 // abcdef \r\n
553 // BOUNDARY \r\n
554 //
555 // zero or one:
556 // Content-Disposition: form-data; name="lsb-release" \r\n \r\n
557 // abcdef \r\n
558 // BOUNDARY \r\n
559 //
560 // zero or one:
561 // Content-Disposition: form-data; name="oom-size" \r\n \r\n
562 // 1234567890 \r\n
563 // BOUNDARY \r\n
564 //
565 // zero or more (up to CrashKeyStorage::num_entries = 64):
566 // Content-Disposition: form-data; name=crash-key-name \r\n
567 // crash-key-value \r\n
568 // BOUNDARY \r\n
569 //
570 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n
571 // Content-Type: application/octet-stream \r\n \r\n
572 // <dump contents>
573 // \r\n BOUNDARY -- \r\n
574
575 MimeWriter writer(temp_file_fd, mime_boundary);
576 {
577 writer.AddBoundary();
578 writer.AddPairString("prod", kProductName);
579 writer.AddBoundary();
580 writer.AddPairString("ver", kVersion);
581 writer.AddBoundary();
582 if (info.pid > 0) {
583 char pid_value_buf[kUint64StringSize];
584 uint64_t pid_value_len = my_uint64_len(info.pid);
585 my_uint64tos(pid_value_buf, info.pid, pid_value_len);
586 static const char pid_key_name[] = "pid";
587 writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1, pid_value_buf,
588 pid_value_len);
589 writer.AddBoundary();
590 }
591 #if defined(OS_ANDROID)
592 // Addtional MIME blocks are added for logging on Android devices.
593 static const char android_build_id[] = "android_build_id";
594 static const char android_build_fp[] = "android_build_fp";
595 static const char device[] = "device";
596 static const char model[] = "model";
597 static const char brand[] = "brand";
598 static const char exception_info[] = "exception_info";
599
600 base::android::BuildInfo* android_build_info =
601 base::android::BuildInfo::GetInstance();
602 writer.AddPairString(android_build_id,
603 android_build_info->android_build_id());
604 writer.AddBoundary();
605 writer.AddPairString(android_build_fp,
606 android_build_info->android_build_fp());
607 writer.AddBoundary();
608 writer.AddPairString(device, android_build_info->device());
609 writer.AddBoundary();
610 writer.AddPairString(model, android_build_info->model());
611 writer.AddBoundary();
612 writer.AddPairString(brand, android_build_info->brand());
613 writer.AddBoundary();
614 if (android_build_info->java_exception_info() != nullptr) {
615 writer.AddPairString(exception_info,
616 android_build_info->java_exception_info());
617 writer.AddBoundary();
618 }
619 #endif
620 writer.Flush();
621 }
622
623 if (info.process_start_time > 0) {
624 struct kernel_timeval tv;
625 if (!sys_gettimeofday(&tv, nullptr)) {
626 uint64_t time = kernel_timeval_to_ms(&tv);
627 if (time > info.process_start_time) {
628 time -= info.process_start_time;
629 char time_str[kUint64StringSize];
630 const unsigned time_len = my_uint64_len(time);
631 my_uint64tos(time_str, time, time_len);
632
633 static const char process_time_msg[] = "ptime";
634 writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
635 time_str, time_len);
636 writer.AddBoundary();
637 writer.Flush();
638 }
639 }
640 }
641
642 if (info.process_type_length) {
643 writer.AddPairString("ptype", info.process_type);
644 writer.AddBoundary();
645 writer.Flush();
646 }
647
648 if (info.distro_length) {
649 static const char distro_msg[] = "lsb-release";
650 writer.AddPairString(distro_msg, info.distro);
651 writer.AddBoundary();
652 writer.Flush();
653 }
654
655 if (info.oom_size) {
656 char oom_size_str[kUint64StringSize];
657 const unsigned oom_size_len = my_uint64_len(info.oom_size);
658 my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
659 static const char oom_size_msg[] = "oom-size";
660 writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1, oom_size_str,
661 oom_size_len);
662 writer.AddBoundary();
663 writer.Flush();
664 }
665
666 if (info.crash_keys) {
667 CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
668 const CrashKeyStorage::Entry* entry;
669 while ((entry = crash_key_iterator.Next())) {
670 writer.AddPairString(entry->key, entry->value);
671 writer.AddBoundary();
672 writer.Flush();
673 }
674 }
675
676 writer.AddFileContents(g_dump_msg, dump_data, dump_size);
677 writer.AddEnd();
678 writer.Flush();
679
680 IGNORE_RET(sys_close(temp_file_fd));
681 }
682
683 bool CrashDone(const MinidumpDescriptor& minidump, const bool succeeded) {
684 // WARNING: this code runs in a compromised context. It may not call into
685 // libc nor allocate memory normally.
686 if (!succeeded) {
687 const char msg[] = "Failed to generate minidump.";
688 WriteLog(msg, sizeof(msg) - 1);
689 return false;
690 }
691
692 DCHECK(!minidump.IsFD());
693
694 BreakpadInfo info = {0};
695 info.filename = minidump.path();
696 info.fd = minidump.fd();
697 info.process_type = "shell";
698 info.process_type_length = 7;
699 info.distro = base::g_linux_distro;
700 info.distro_length = my_strlen(base::g_linux_distro);
701 info.process_start_time = g_process_start_time;
702 info.oom_size = base::g_oom_size;
703 info.pid = g_pid;
704 info.crash_keys = g_crash_keys;
705 HandleCrashDump(info);
706 #if defined(OS_ANDROID)
707 return FinalizeCrashDoneAndroid();
708 #else
709 return true;
710 #endif
711 }
712
713 // Wrapper function, do not add more code here.
714 bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
715 void* context,
716 bool succeeded) {
717 LOG(WARNING) << "CrashDoneNoUpload";
718 return CrashDone(minidump, succeeded);
719 }
720
721 void EnableCrashDumping(const base::FilePath& dumps_path) {
722 g_is_crash_reporter_enabled = true;
723
724 DCHECK(!g_breakpad);
725 DCHECK(base::CreateDirectoryAndGetError(dumps_path, nullptr));
726 MinidumpDescriptor minidump_descriptor(dumps_path.value());
727 minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
728 g_breakpad = new ExceptionHandler(
729 minidump_descriptor, nullptr, CrashDoneNoUpload, nullptr,
730 true, // Install handlers.
731 -1); // Server file descriptor. -1 for in-process.
732 }
733
734 void SetCrashKeyValue(const base::StringPiece& key,
735 const base::StringPiece& value) {
736 g_crash_keys->SetKeyValue(key.data(), value.data());
737 }
738
739 void ClearCrashKey(const base::StringPiece& key) {
740 g_crash_keys->RemoveKey(key.data());
741 }
742
743 void RegisterCrashKeys() {
744 // TODO(qsr): Is there any key we want to put.
viettrungluu 2015/07/28 16:45:05 nit: '?' instead of '.'
qsr 2015/07/29 09:00:47 Done.
745 }
746
747 void InitCrashKeys() {
748 g_crash_keys = new CrashKeyStorage;
749 RegisterCrashKeys();
750 base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey);
751 }
752
753 // Miscellaneous initialization functions to call after Breakpad has been
754 // enabled.
755 void PostEnableBreakpadInitialization() {
756 SetProcessStartTime();
757 g_pid = getpid();
758
759 base::debug::SetDumpWithoutCrashingFunction(&DumpProcess);
760 }
761
762 } // namespace
763
764 void InitCrashReporter(const base::FilePath& dumps_path) {
765 #if defined(OS_ANDROID)
766 // This will guarantee that the BuildInfo has been initialized and subsequent
767 // calls will not require memory allocation.
768 base::android::BuildInfo::GetInstance();
769 #endif
770
771 InitCrashKeys();
772 EnableCrashDumping(dumps_path);
773
774 PostEnableBreakpadInitialization();
775 }
776
777 bool IsCrashReporterEnabled() {
778 return g_is_crash_reporter_enabled;
779 }
780
781 } // namespace breakpad
OLDNEW
« DEPS ('K') | « shell/crash/breakpad.h ('k') | third_party/breakpad/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698