| 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> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 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" |
| 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, they are only destroyed |
| 68 // destroyed at the end of the processes lifetime, which is greater in span than | 66 // at 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))); |
| 94 } | 97 } |
| 95 | 98 |
| 96 CrashHandlerHostLinux::~CrashHandlerHostLinux() { | 99 CrashHandlerHostLinux::~CrashHandlerHostLinux() { |
| 97 (void) HANDLE_EINTR(close(process_socket_)); | 100 (void) HANDLE_EINTR(close(process_socket_)); |
| 98 (void) HANDLE_EINTR(close(browser_socket_)); | 101 (void) HANDLE_EINTR(close(browser_socket_)); |
| 99 } | 102 } |
| 100 | 103 |
| 104 void CrashHandlerHostLinux::StartUploaderThread() { |
| 105 uploader_thread_.reset( |
| 106 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str())); |
| 107 uploader_thread_->Start(); |
| 108 } |
| 109 |
| 101 void CrashHandlerHostLinux::Init() { | 110 void CrashHandlerHostLinux::Init() { |
| 102 base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); | 111 base::MessageLoopForIO* ml = base::MessageLoopForIO::current(); |
| 103 CHECK(ml->WatchFileDescriptor( | 112 CHECK(ml->WatchFileDescriptor( |
| 104 browser_socket_, true /* persistent */, | 113 browser_socket_, true /* persistent */, |
| 105 base::MessageLoopForIO::WATCH_READ, | 114 base::MessageLoopForIO::WATCH_READ, |
| 106 &file_descriptor_watcher_, this)); | 115 &file_descriptor_watcher_, this)); |
| 107 ml->AddDestructionObserver(this); | 116 ml->AddDestructionObserver(this); |
| 108 } | 117 } |
| 109 | 118 |
| 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) { | 119 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { |
| 118 NOTREACHED(); | 120 NOTREACHED(); |
| 119 } | 121 } |
| 120 | 122 |
| 121 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { | 123 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { |
| 122 DCHECK_EQ(fd, browser_socket_); | 124 DCHECK_EQ(fd, browser_socket_); |
| 123 | 125 |
| 124 // A process has crashed and has signaled us by writing a datagram | 126 // 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 | 127 // 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 | 128 // 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); | 325 process_type_.copy(process_type_str, info->process_type_length); |
| 324 process_type_str[info->process_type_length] = '\0'; | 326 process_type_str[info->process_type_length] = '\0'; |
| 325 info->process_type = process_type_str; | 327 info->process_type = process_type_str; |
| 326 | 328 |
| 327 info->distro_length = strlen(distro); | 329 info->distro_length = strlen(distro); |
| 328 info->distro = distro; | 330 info->distro = distro; |
| 329 #if defined(OS_ANDROID) | 331 #if defined(OS_ANDROID) |
| 330 // Nothing gets uploaded in android. | 332 // Nothing gets uploaded in android. |
| 331 info->upload = false; | 333 info->upload = false; |
| 332 #else | 334 #else |
| 333 info->upload = (getenv(env_vars::kHeadless) == NULL); | 335 info->upload = upload_; |
| 334 #endif | 336 #endif |
| 335 | 337 |
| 336 info->crash_keys = crash_keys; | 338 info->crash_keys = crash_keys; |
| 337 | 339 |
| 338 #if defined(ADDRESS_SANITIZER) | 340 #if defined(ADDRESS_SANITIZER) |
| 339 info->asan_report_str = asan_report_str_; | 341 info->asan_report_str = asan_report_str_; |
| 340 info->asan_report_length = strlen(asan_report_str_); | 342 info->asan_report_length = strlen(asan_report_str_); |
| 341 #endif | 343 #endif |
| 342 info->process_start_time = uptime; | 344 info->process_start_time = uptime; |
| 343 info->oom_size = oom_size; | 345 info->oom_size = oom_size; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 356 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, | 358 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, |
| 357 pid_t crashing_pid, | 359 pid_t crashing_pid, |
| 358 char* crash_context, | 360 char* crash_context, |
| 359 int signal_fd) { | 361 int signal_fd) { |
| 360 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( | 362 DCHECK(BrowserThread::GetBlockingPool()->IsRunningSequenceOnCurrentThread( |
| 361 worker_pool_token_)); | 363 worker_pool_token_)); |
| 362 | 364 |
| 363 base::FilePath dumps_path("/tmp"); | 365 base::FilePath dumps_path("/tmp"); |
| 364 PathService::Get(base::DIR_TEMP, &dumps_path); | 366 PathService::Get(base::DIR_TEMP, &dumps_path); |
| 365 if (!info->upload) | 367 if (!info->upload) |
| 366 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); | 368 dumps_path = dumps_path_; |
| 367 const uint64 rand = base::RandUint64(); | 369 const uint64 rand = base::RandUint64(); |
| 368 const std::string minidump_filename = | 370 const std::string minidump_filename = |
| 369 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", | 371 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", |
| 370 dumps_path.value().c_str(), | 372 dumps_path.value().c_str(), |
| 371 process_type_.c_str(), | 373 process_type_.c_str(), |
| 372 rand); | 374 rand); |
| 373 | 375 |
| 374 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), | 376 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |
| 375 kMaxMinidumpFileSize, | 377 kMaxMinidumpFileSize, |
| 376 crashing_pid, crash_context, | 378 crashing_pid, crash_context, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 | 443 |
| 442 // If we are quitting and there are crash dumps in the queue, turn them into | 444 // If we are quitting and there are crash dumps in the queue, turn them into |
| 443 // no-ops. | 445 // no-ops. |
| 444 shutting_down_ = true; | 446 shutting_down_ = true; |
| 445 uploader_thread_->Stop(); | 447 uploader_thread_->Stop(); |
| 446 } | 448 } |
| 447 | 449 |
| 448 bool CrashHandlerHostLinux::IsShuttingDown() const { | 450 bool CrashHandlerHostLinux::IsShuttingDown() const { |
| 449 return shutting_down_; | 451 return shutting_down_; |
| 450 } | 452 } |
| 451 | |
| 452 ExtensionCrashHandlerHostLinux::ExtensionCrashHandlerHostLinux() { | |
| 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 |