Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/crash_handler_host_linux.h" | 5 #include "chrome/browser/crash_handler_host_linux.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| 11 #include <unistd.h> | 11 #include <unistd.h> |
| 12 | 12 |
| 13 #include "base/bind.h" | 13 #include "base/bind.h" |
| 14 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
| 15 #include "base/files/file_path.h" | 15 #include "base/files/file_path.h" |
| 16 #include "base/format_macros.h" | 16 #include "base/format_macros.h" |
| 17 #include "base/linux_util.h" | 17 #include "base/linux_util.h" |
| 18 #include "base/logging.h" | 18 #include "base/logging.h" |
| 19 #include "base/memory/singleton.h" | 19 #include "base/memory/singleton.h" |
| 20 #include "base/message_loop/message_loop.h" | 20 #include "base/message_loop/message_loop.h" |
| 21 #include "base/path_service.h" | 21 #include "base/path_service.h" |
| 22 #include "base/posix/eintr_wrapper.h" | 22 #include "base/posix/eintr_wrapper.h" |
| 23 #include "base/rand_util.h" | 23 #include "base/rand_util.h" |
| 24 #include "base/strings/string_util.h" | 24 #include "base/strings/string_util.h" |
| 25 #include "base/strings/stringprintf.h" | 25 #include "base/strings/stringprintf.h" |
| 26 #include "base/threading/thread.h" | 26 #include "base/threading/thread.h" |
| 27 #include "breakpad/src/client/linux/handler/exception_handler.h" | 27 #include "breakpad/src/client/linux/handler/exception_handler.h" |
| 28 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" | 28 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" |
| 29 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" | 29 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" |
| 30 #include "chrome/app/breakpad_linux_impl.h" | 30 #include "chrome/app/breakpad_linux_impl.h" |
|
Nico
2013/10/19 01:28:46
This is for a folllow-up I suppose.
jochen (gone - plz use gerrit)
2013/10/19 02:38:36
Right, those files will be moved all together to t
| |
| 31 #include "chrome/common/chrome_paths.h" | |
| 32 #include "chrome/common/env_vars.h" | |
| 33 #include "content/public/browser/browser_thread.h" | 31 #include "content/public/browser/browser_thread.h" |
| 34 | 32 |
| 35 #if defined(OS_ANDROID) | 33 #if defined(OS_ANDROID) |
| 36 #include <sys/linux-syscalls.h> | 34 #include <sys/linux-syscalls.h> |
| 37 | 35 |
| 38 #define SYS_read __NR_read | 36 #define SYS_read __NR_read |
| 39 #endif | 37 #endif |
| 40 | 38 |
| 41 using content::BrowserThread; | 39 using content::BrowserThread; |
| 42 using google_breakpad::ExceptionHandler; | 40 using google_breakpad::ExceptionHandler; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 57 HandleCrashDump(*info); | 55 HandleCrashDump(*info); |
| 58 delete[] info->filename; | 56 delete[] info->filename; |
| 59 delete[] info->process_type; | 57 delete[] info->process_type; |
| 60 delete[] info->distro; | 58 delete[] info->distro; |
| 61 delete info->crash_keys; | 59 delete info->crash_keys; |
| 62 delete info; | 60 delete info; |
| 63 } | 61 } |
| 64 | 62 |
| 65 } // namespace | 63 } // namespace |
| 66 | 64 |
| 67 // Since classes derived from CrashHandlerHostLinux are singletons, it's only | 65 // Since instances of CrashHandlerHostLinux are leaked, it's only destroyed at |
|
Nico
2013/10/19 01:28:46
s/it's/they are/ :-P
jochen (gone - plz use gerrit)
2013/10/19 02:38:36
Done.
| |
| 68 // destroyed at the end of the processes lifetime, which is greater in span than | 66 // the end of the processes lifetime, which is greater in span than the |
| 69 // the lifetime of the IO message loop. Thus, all calls to base::Bind() use | 67 // lifetime of the IO message loop. Thus, all calls to base::Bind() use |
| 70 // non-refcounted pointers. | 68 // non-refcounted pointers. |
| 71 | 69 |
| 72 CrashHandlerHostLinux::CrashHandlerHostLinux() | 70 CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type, |
| 73 : shutting_down_(false), | 71 const base::FilePath& dumps_path, |
| 72 bool upload) | |
| 73 : process_type_(process_type), | |
| 74 dumps_path_(dumps_path), | |
| 75 upload_(upload), | |
| 76 shutting_down_(false), | |
| 74 worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()) { | 77 worker_pool_token_(BrowserThread::GetBlockingPool()->GetSequenceToken()) { |
| 75 int fds[2]; | 78 int fds[2]; |
| 76 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from | 79 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from |
| 77 // sending datagrams to other sockets on the system. The sandbox may prevent | 80 // sending datagrams to other sockets on the system. The sandbox may prevent |
| 78 // the process from calling socket() to create new sockets, but it'll still | 81 // the process from calling socket() to create new sockets, but it'll still |
| 79 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send | 82 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send |
| 80 // a datagram to any (abstract) socket on the same system. With | 83 // a datagram to any (abstract) socket on the same system. With |
| 81 // SOCK_SEQPACKET, this is prevented. | 84 // SOCK_SEQPACKET, this is prevented. |
| 82 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0); | 85 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0); |
| 83 static const int on = 1; | 86 static const int on = 1; |
| 84 | 87 |
| 85 // Enable passcred on the server end of the socket | 88 // Enable passcred on the server end of the socket |
| 86 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0); | 89 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0); |
| 87 | 90 |
| 88 process_socket_ = fds[0]; | 91 process_socket_ = fds[0]; |
| 89 browser_socket_ = fds[1]; | 92 browser_socket_ = fds[1]; |
| 90 | 93 |
| 91 BrowserThread::PostTask( | 94 BrowserThread::PostTask( |
| 92 BrowserThread::IO, FROM_HERE, | 95 BrowserThread::IO, FROM_HERE, |
| 93 base::Bind(&CrashHandlerHostLinux::Init, base::Unretained(this))); | 96 base::Bind(&CrashHandlerHostLinux::Init, base::Unretained(this))); |
| 97 | |
| 98 uploader_thread_.reset( | |
| 99 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str())); | |
| 100 uploader_thread_->Start(); | |
|
Nico
2013/10/19 01:28:46
Can this stay in a method? Constructors that start
jochen (gone - plz use gerrit)
2013/10/19 02:38:36
Done.
| |
| 94 } | 101 } |
| 95 | 102 |
| 96 CrashHandlerHostLinux::~CrashHandlerHostLinux() { | 103 CrashHandlerHostLinux::~CrashHandlerHostLinux() { |
| 97 (void) HANDLE_EINTR(close(process_socket_)); | 104 (void) HANDLE_EINTR(close(process_socket_)); |
| 98 (void) HANDLE_EINTR(close(browser_socket_)); | 105 (void) HANDLE_EINTR(close(browser_socket_)); |
| 99 } | 106 } |
| 100 | 107 |
| 101 void CrashHandlerHostLinux::Init() { | 108 void CrashHandlerHostLinux::Init() { |
| 102 base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); | 109 base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); |
| 103 CHECK(ml->WatchFileDescriptor( | 110 CHECK(ml->WatchFileDescriptor( |
| 104 browser_socket_, true /* persistent */, | 111 browser_socket_, true /* persistent */, |
| 105 base::MessageLoopForIO::WATCH_READ, | 112 base::MessageLoopForIO::WATCH_READ, |
| 106 &file_descriptor_watcher_, this)); | 113 &file_descriptor_watcher_, this)); |
| 107 ml->AddDestructionObserver(this); | 114 ml->AddDestructionObserver(this); |
| 108 } | 115 } |
| 109 | 116 |
| 110 void CrashHandlerHostLinux::InitCrashUploaderThread() { | |
| 111 SetProcessType(); | |
| 112 uploader_thread_.reset( | |
| 113 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str())); | |
| 114 uploader_thread_->Start(); | |
| 115 } | |
| 116 | |
| 117 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { | 117 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { |
| 118 NOTREACHED(); | 118 NOTREACHED(); |
| 119 } | 119 } |
| 120 | 120 |
| 121 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { | 121 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { |
| 122 DCHECK_EQ(fd, browser_socket_); | 122 DCHECK_EQ(fd, browser_socket_); |
| 123 | 123 |
| 124 // A process has crashed and has signaled us by writing a datagram | 124 // A process has crashed and has signaled us by writing a datagram |
| 125 // to the death signal socket. The datagram contains the crash context needed | 125 // to the death signal socket. The datagram contains the crash context needed |
| 126 // for writing the minidump as well as a file descriptor and a credentials | 126 // for writing the minidump as well as a file descriptor and a credentials |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 323 process_type_.copy(process_type_str, info->process_type_length); | 323 process_type_.copy(process_type_str, info->process_type_length); |
| 324 process_type_str[info->process_type_length] = '\0'; | 324 process_type_str[info->process_type_length] = '\0'; |
| 325 info->process_type = process_type_str; | 325 info->process_type = process_type_str; |
| 326 | 326 |
| 327 info->distro_length = strlen(distro); | 327 info->distro_length = strlen(distro); |
| 328 info->distro = distro; | 328 info->distro = distro; |
| 329 #if defined(OS_ANDROID) | 329 #if defined(OS_ANDROID) |
| 330 // Nothing gets uploaded in android. | 330 // Nothing gets uploaded in android. |
| 331 info->upload = false; | 331 info->upload = false; |
| 332 #else | 332 #else |
| 333 info->upload = (getenv(env_vars::kHeadless) == NULL); | 333 info->upload = upload_; |
| 334 #endif | 334 #endif |
| 335 | 335 |
| 336 info->crash_keys = crash_keys; | 336 info->crash_keys = crash_keys; |
| 337 | 337 |
| 338 #if defined(ADDRESS_SANITIZER) | 338 #if defined(ADDRESS_SANITIZER) |
| 339 info->asan_report_str = asan_report_str_; | 339 info->asan_report_str = asan_report_str_; |
| 340 info->asan_report_length = strlen(asan_report_str_); | 340 info->asan_report_length = strlen(asan_report_str_); |
| 341 #endif | 341 #endif |
| 342 info->process_start_time = uptime; | 342 info->process_start_time = uptime; |
| 343 info->oom_size = oom_size; | 343 info->oom_size = oom_size; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 356 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, | 356 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, |
| 357 pid_t crashing_pid, | 357 pid_t crashing_pid, |
| 358 char* crash_context, | 358 char* crash_context, |
| 359 int signal_fd) { | 359 int signal_fd) { |
| 360 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( | 360 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( |
| 361 worker_pool_token_)); | 361 worker_pool_token_)); |
| 362 | 362 |
| 363 base::FilePath dumps_path("/tmp"); | 363 base::FilePath dumps_path("/tmp"); |
| 364 PathService::Get(base::DIR_TEMP, &dumps_path); | 364 PathService::Get(base::DIR_TEMP, &dumps_path); |
| 365 if (!info->upload) | 365 if (!info->upload) |
| 366 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); | 366 dumps_path = dumps_path_; |
| 367 const uint64 rand = base::RandUint64(); | 367 const uint64 rand = base::RandUint64(); |
| 368 const std::string minidump_filename = | 368 const std::string minidump_filename = |
| 369 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", | 369 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", |
| 370 dumps_path.value().c_str(), | 370 dumps_path.value().c_str(), |
| 371 process_type_.c_str(), | 371 process_type_.c_str(), |
| 372 rand); | 372 rand); |
| 373 | 373 |
| 374 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), | 374 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |
| 375 kMaxMinidumpFileSize, | 375 kMaxMinidumpFileSize, |
| 376 crashing_pid, crash_context, | 376 crashing_pid, crash_context, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 | 441 |
| 442 // If we are quitting and there are crash dumps in the queue, turn them into | 442 // If we are quitting and there are crash dumps in the queue, turn them into |
| 443 // no-ops. | 443 // no-ops. |
| 444 shutting_down_ = true; | 444 shutting_down_ = true; |
| 445 uploader_thread_->Stop(); | 445 uploader_thread_->Stop(); |
| 446 } | 446 } |
| 447 | 447 |
| 448 bool CrashHandlerHostLinux::IsShuttingDown() const { | 448 bool CrashHandlerHostLinux::IsShuttingDown() const { |
| 449 return shutting_down_; | 449 return shutting_down_; |
| 450 } | 450 } |
| 451 | |
| 452 ExtensionCrashHandlerHostLinux::ExtensionCrashHandlerHostLinux() { | |
|
Nico
2013/10/19 01:28:46
These classes were weird.
| |
| 453 InitCrashUploaderThread(); | |
| 454 } | |
| 455 | |
| 456 ExtensionCrashHandlerHostLinux::~ExtensionCrashHandlerHostLinux() { | |
| 457 } | |
| 458 | |
| 459 void ExtensionCrashHandlerHostLinux::SetProcessType() { | |
| 460 process_type_ = "extension"; | |
| 461 } | |
| 462 | |
| 463 // static | |
| 464 ExtensionCrashHandlerHostLinux* ExtensionCrashHandlerHostLinux::GetInstance() { | |
| 465 return Singleton<ExtensionCrashHandlerHostLinux>::get(); | |
| 466 } | |
| 467 | |
| 468 GpuCrashHandlerHostLinux::GpuCrashHandlerHostLinux() { | |
| 469 InitCrashUploaderThread(); | |
| 470 } | |
| 471 | |
| 472 GpuCrashHandlerHostLinux::~GpuCrashHandlerHostLinux() { | |
| 473 } | |
| 474 | |
| 475 void GpuCrashHandlerHostLinux::SetProcessType() { | |
| 476 process_type_ = "gpu-process"; | |
| 477 } | |
| 478 | |
| 479 // static | |
| 480 GpuCrashHandlerHostLinux* GpuCrashHandlerHostLinux::GetInstance() { | |
| 481 return Singleton<GpuCrashHandlerHostLinux>::get(); | |
| 482 } | |
| 483 | |
| 484 PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() { | |
| 485 InitCrashUploaderThread(); | |
| 486 } | |
| 487 | |
| 488 PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() { | |
| 489 } | |
| 490 | |
| 491 void PluginCrashHandlerHostLinux::SetProcessType() { | |
| 492 process_type_ = "plugin"; | |
| 493 } | |
| 494 | |
| 495 // static | |
| 496 PluginCrashHandlerHostLinux* PluginCrashHandlerHostLinux::GetInstance() { | |
| 497 return Singleton<PluginCrashHandlerHostLinux>::get(); | |
| 498 } | |
| 499 | |
| 500 PpapiCrashHandlerHostLinux::PpapiCrashHandlerHostLinux() { | |
| 501 InitCrashUploaderThread(); | |
| 502 } | |
| 503 | |
| 504 PpapiCrashHandlerHostLinux::~PpapiCrashHandlerHostLinux() { | |
| 505 } | |
| 506 | |
| 507 void PpapiCrashHandlerHostLinux::SetProcessType() { | |
| 508 process_type_ = "ppapi"; | |
| 509 } | |
| 510 | |
| 511 // static | |
| 512 PpapiCrashHandlerHostLinux* PpapiCrashHandlerHostLinux::GetInstance() { | |
| 513 return Singleton<PpapiCrashHandlerHostLinux>::get(); | |
| 514 } | |
| 515 | |
| 516 RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() { | |
| 517 InitCrashUploaderThread(); | |
| 518 } | |
| 519 | |
| 520 RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() { | |
| 521 } | |
| 522 | |
| 523 void RendererCrashHandlerHostLinux::SetProcessType() { | |
| 524 process_type_ = "renderer"; | |
| 525 } | |
| 526 | |
| 527 // static | |
| 528 RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() { | |
| 529 return Singleton<RendererCrashHandlerHostLinux>::get(); | |
| 530 } | |
| OLD | NEW |