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

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

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

Powered by Google App Engine
This is Rietveld 408576698