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

Side by Side Diff: chrome/browser/crash_handler_host_posix.cc

Issue 9838033: Upstream native crash handling changes for Android. (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: In response to comments. Lots of linux to posix Created 8 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_posix.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/eintr_wrapper.h" 15 #include "base/eintr_wrapper.h"
16 #include "base/file_path.h" 16 #include "base/file_path.h"
17 #include "base/format_macros.h" 17 #include "base/format_macros.h"
18 #include "base/linux_util.h" 18 #include "base/linux_util.h"
19 #include "base/logging.h" 19 #include "base/logging.h"
20 #include "base/memory/singleton.h" 20 #include "base/memory/singleton.h"
21 #include "base/message_loop.h" 21 #include "base/message_loop.h"
22 #include "base/path_service.h" 22 #include "base/path_service.h"
23 #include "base/rand_util.h" 23 #include "base/rand_util.h"
24 #include "base/string_util.h" 24 #include "base/string_util.h"
25 #include "base/stringprintf.h" 25 #include "base/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.h" 30 #include "chrome/app/breakpad_linux.h"
31 #include "chrome/common/chrome_paths.h" 31 #include "chrome/common/chrome_paths.h"
32 #include "chrome/common/env_vars.h" 32 #include "chrome/common/env_vars.h"
33 #include "content/public/browser/browser_thread.h" 33 #include "content/public/browser/browser_thread.h"
34 34
35 #if defined(OS_ANDROID)
36 #include <sys/linux-syscalls.h>
37
38 #define SYS_read __NR_read
39 #endif
40
35 using content::BrowserThread; 41 using content::BrowserThread;
36 using google_breakpad::ExceptionHandler; 42 using google_breakpad::ExceptionHandler;
37 43
38 namespace { 44 namespace {
39 45
40 // The length of the control message: 46 // The length of the control message:
41 const unsigned kControlMsgSize = 47 const unsigned kControlMsgSize =
42 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); 48 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
43 // The length of the regular payload: 49 // The length of the regular payload:
44 const unsigned kCrashContextSize = sizeof(ExceptionHandler::CrashContext); 50 const unsigned kCrashContextSize = sizeof(ExceptionHandler::CrashContext);
45 51
46 // Handles the crash dump and frees the allocated BreakpadInfo struct. 52 // Handles the crash dump and frees the allocated BreakpadInfo struct.
47 void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) { 53 void CrashDumpTask(CrashHandlerHostPosix* handler, BreakpadInfo* info) {
48 if (handler->IsShuttingDown()) 54 if (handler->IsShuttingDown())
49 return; 55 return;
50 56
51 HandleCrashDump(*info); 57 HandleCrashDump(*info);
52 delete[] info->filename; 58 delete[] info->filename;
53 delete[] info->process_type; 59 delete[] info->process_type;
54 delete[] info->crash_url; 60 delete[] info->crash_url;
55 delete[] info->guid; 61 delete[] info->guid;
56 delete[] info->distro; 62 delete[] info->distro;
57 delete info; 63 delete info;
58 } 64 }
59 65
60 } // namespace 66 } // namespace
61 67
62 // Since classes derived from CrashHandlerHostLinux are singletons, it's only 68 // Since classes derived from CrashHandlerHostPosix are singletons, it's only
63 // destroyed at the end of the processes lifetime, which is greater in span than 69 // destroyed at the end of the processes lifetime, which is greater in span than
64 // the lifetime of the IO message loop. Thus, all calls to base::Bind() use 70 // the lifetime of the IO message loop. Thus, all calls to base::Bind() use
65 // non-refcounted pointers. 71 // non-refcounted pointers.
66 72
67 CrashHandlerHostLinux::CrashHandlerHostLinux() 73 CrashHandlerHostPosix::CrashHandlerHostPosix()
68 : shutting_down_(false) { 74 : shutting_down_(false) {
69 int fds[2]; 75 int fds[2];
70 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from 76 // We use SOCK_SEQPACKET rather than SOCK_DGRAM to prevent the process from
71 // sending datagrams to other sockets on the system. The sandbox may prevent 77 // sending datagrams to other sockets on the system. The sandbox may prevent
72 // the process from calling socket() to create new sockets, but it'll still 78 // the process from calling socket() to create new sockets, but it'll still
73 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send 79 // inherit some sockets. With PF_UNIX+SOCK_DGRAM, it can call sendmsg to send
74 // a datagram to any (abstract) socket on the same system. With 80 // a datagram to any (abstract) socket on the same system. With
75 // SOCK_SEQPACKET, this is prevented. 81 // SOCK_SEQPACKET, this is prevented.
76 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0); 82 CHECK_EQ(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds), 0);
77 static const int on = 1; 83 static const int on = 1;
78 84
79 // Enable passcred on the server end of the socket 85 // Enable passcred on the server end of the socket
80 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0); 86 CHECK_EQ(setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)), 0);
81 87
82 process_socket_ = fds[0]; 88 process_socket_ = fds[0];
83 browser_socket_ = fds[1]; 89 browser_socket_ = fds[1];
84 90
85 BrowserThread::PostTask( 91 BrowserThread::PostTask(
86 BrowserThread::IO, FROM_HERE, 92 BrowserThread::IO, FROM_HERE,
87 base::Bind(&CrashHandlerHostLinux::Init, base::Unretained(this))); 93 base::Bind(&CrashHandlerHostPosix::Init, base::Unretained(this)));
88 } 94 }
89 95
90 CrashHandlerHostLinux::~CrashHandlerHostLinux() { 96 CrashHandlerHostPosix::~CrashHandlerHostPosix() {
91 HANDLE_EINTR(close(process_socket_)); 97 HANDLE_EINTR(close(process_socket_));
92 HANDLE_EINTR(close(browser_socket_)); 98 HANDLE_EINTR(close(browser_socket_));
93 } 99 }
94 100
95 void CrashHandlerHostLinux::Init() { 101 void CrashHandlerHostPosix::Init() {
96 MessageLoopForIO* ml = MessageLoopForIO::current(); 102 MessageLoopForIO* ml = MessageLoopForIO::current();
97 CHECK(ml->WatchFileDescriptor( 103 CHECK(ml->WatchFileDescriptor(
98 browser_socket_, true /* persistent */, 104 browser_socket_, true /* persistent */,
99 MessageLoopForIO::WATCH_READ, 105 MessageLoopForIO::WATCH_READ,
100 &file_descriptor_watcher_, this)); 106 &file_descriptor_watcher_, this));
101 ml->AddDestructionObserver(this); 107 ml->AddDestructionObserver(this);
102 } 108 }
103 109
104 void CrashHandlerHostLinux::InitCrashUploaderThread() { 110 void CrashHandlerHostPosix::InitCrashUploaderThread() {
105 SetProcessType(); 111 SetProcessType();
106 uploader_thread_.reset( 112 uploader_thread_.reset(
107 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str())); 113 new base::Thread(std::string(process_type_ + "_crash_uploader").c_str()));
108 uploader_thread_->Start(); 114 uploader_thread_->Start();
109 } 115 }
110 116
111 void CrashHandlerHostLinux::OnFileCanWriteWithoutBlocking(int fd) { 117 void CrashHandlerHostPosix::OnFileCanWriteWithoutBlocking(int fd) {
112 DCHECK(false); 118 DCHECK(false);
113 } 119 }
114 120
115 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { 121 void CrashHandlerHostPosix::OnFileCanReadWithoutBlocking(int fd) {
116 DCHECK_EQ(fd, browser_socket_); 122 DCHECK_EQ(fd, browser_socket_);
117 123
118 // 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
119 // 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
120 // 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
121 // block so that they can't lie about their pid. 127 // block so that they can't lie about their pid.
122 128
123 const size_t kIovSize = 7; 129 const size_t kIovSize = 7;
124 struct msghdr msg = {0}; 130 struct msghdr msg = {0};
125 struct iovec iov[kIovSize]; 131 struct iovec iov[kIovSize];
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 info->process_type = process_type_str; 311 info->process_type = process_type_str;
306 312
307 info->crash_url_length = strlen(crash_url); 313 info->crash_url_length = strlen(crash_url);
308 info->crash_url = crash_url; 314 info->crash_url = crash_url;
309 315
310 info->guid_length = strlen(guid); 316 info->guid_length = strlen(guid);
311 info->guid = guid; 317 info->guid = guid;
312 318
313 info->distro_length = strlen(distro); 319 info->distro_length = strlen(distro);
314 info->distro = distro; 320 info->distro = distro;
315 321 #if defined(OS_ANDROID)
322 // Nothing gets uploaded in android.
323 info->upload = false;
324 #else
316 info->upload = (getenv(env_vars::kHeadless) == NULL); 325 info->upload = (getenv(env_vars::kHeadless) == NULL);
326 #endif
317 info->process_start_time = uptime; 327 info->process_start_time = uptime;
318 328
319 BrowserThread::PostTask( 329 BrowserThread::PostTask(
320 BrowserThread::FILE, FROM_HERE, 330 BrowserThread::FILE, FROM_HERE,
321 base::Bind(&CrashHandlerHostLinux::WriteDumpFile, 331 base::Bind(&CrashHandlerHostPosix::WriteDumpFile,
322 base::Unretained(this), 332 base::Unretained(this),
323 info, 333 info,
324 crashing_pid, 334 crashing_pid,
325 crash_context, 335 crash_context,
326 signal_fd)); 336 signal_fd));
327 } 337 }
328 338
329 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, 339 void CrashHandlerHostPosix::WriteDumpFile(BreakpadInfo* info,
330 pid_t crashing_pid, 340 pid_t crashing_pid,
331 char* crash_context, 341 char* crash_context,
332 int signal_fd) { 342 int signal_fd) {
333 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
334 344
335 FilePath dumps_path("/tmp"); 345 FilePath dumps_path("/tmp");
336 PathService::Get(base::DIR_TEMP, &dumps_path); 346 PathService::Get(base::DIR_TEMP, &dumps_path);
337 if (!info->upload) 347 if (!info->upload)
338 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); 348 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
339 const uint64 rand = base::RandUint64(); 349 const uint64 rand = base::RandUint64();
340 const std::string minidump_filename = 350 const std::string minidump_filename =
341 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", 351 base::StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp",
342 dumps_path.value().c_str(), 352 dumps_path.value().c_str(),
343 process_type_.c_str(), 353 process_type_.c_str(),
344 rand); 354 rand);
345 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), 355 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(),
346 crashing_pid, crash_context, 356 crashing_pid, crash_context,
347 kCrashContextSize)) { 357 kCrashContextSize)) {
348 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; 358 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid;
349 } 359 }
350 delete[] crash_context; 360 delete[] crash_context;
351 361
352 // Freed in CrashDumpTask(); 362 // Freed in CrashDumpTask();
353 char* minidump_filename_str = new char[minidump_filename.length() + 1]; 363 unsigned minidump_filename_str_len = minidump_filename.length() + 1;
364 char* minidump_filename_str = new char[minidump_filename_str_len];
354 minidump_filename.copy(minidump_filename_str, minidump_filename.length()); 365 minidump_filename.copy(minidump_filename_str, minidump_filename.length());
355 minidump_filename_str[minidump_filename.length()] = '\0'; 366 minidump_filename_str[minidump_filename.length()] = '\0';
356 info->filename = minidump_filename_str; 367 info->filename = minidump_filename_str;
368 info->filename_length = minidump_filename_str_len;
369 info->pid = crashing_pid;
357 370
358 BrowserThread::PostTask( 371 BrowserThread::PostTask(
359 BrowserThread::IO, FROM_HERE, 372 BrowserThread::IO, FROM_HERE,
360 base::Bind(&CrashHandlerHostLinux::QueueCrashDumpTask, 373 base::Bind(&CrashHandlerHostPosix::QueueCrashDumpTask,
361 base::Unretained(this), 374 base::Unretained(this),
362 info, 375 info,
363 signal_fd)); 376 signal_fd));
364 } 377 }
365 378
366 void CrashHandlerHostLinux::QueueCrashDumpTask(BreakpadInfo* info, 379 void CrashHandlerHostPosix::QueueCrashDumpTask(BreakpadInfo* info,
367 int signal_fd) { 380 int signal_fd) {
368 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 381 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
369 382
370 // Send the done signal to the process: it can exit now. 383 // Send the done signal to the process: it can exit now.
371 struct msghdr msg = {0}; 384 struct msghdr msg = {0};
372 struct iovec done_iov; 385 struct iovec done_iov;
373 done_iov.iov_base = const_cast<char*>("\x42"); 386 done_iov.iov_base = const_cast<char*>("\x42");
374 done_iov.iov_len = 1; 387 done_iov.iov_len = 1;
375 msg.msg_iov = &done_iov; 388 msg.msg_iov = &done_iov;
376 msg.msg_iovlen = 1; 389 msg.msg_iovlen = 1;
377 390
378 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); 391 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL));
379 HANDLE_EINTR(close(signal_fd)); 392 HANDLE_EINTR(close(signal_fd));
380 393
381 uploader_thread_->message_loop()->PostTask( 394 uploader_thread_->message_loop()->PostTask(
382 FROM_HERE, 395 FROM_HERE,
383 base::Bind(&CrashDumpTask, base::Unretained(this), info)); 396 base::Bind(&CrashDumpTask, base::Unretained(this), info));
384 } 397 }
385 398
386 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { 399 void CrashHandlerHostPosix::WillDestroyCurrentMessageLoop() {
387 file_descriptor_watcher_.StopWatchingFileDescriptor(); 400 file_descriptor_watcher_.StopWatchingFileDescriptor();
388 401
389 // If we are quitting and there are crash dumps in the queue, turn them into 402 // If we are quitting and there are crash dumps in the queue, turn them into
390 // no-ops. 403 // no-ops.
391 shutting_down_ = true; 404 shutting_down_ = true;
392 uploader_thread_->Stop(); 405 uploader_thread_->Stop();
393 } 406 }
394 407
395 bool CrashHandlerHostLinux::IsShuttingDown() const { 408 bool CrashHandlerHostPosix::IsShuttingDown() const {
396 return shutting_down_; 409 return shutting_down_;
397 } 410 }
398 411
399 ExtensionCrashHandlerHostLinux::ExtensionCrashHandlerHostLinux() { 412 ExtensionCrashHandlerHostPosix::ExtensionCrashHandlerHostPosix() {
400 InitCrashUploaderThread(); 413 InitCrashUploaderThread();
401 } 414 }
402 415
403 ExtensionCrashHandlerHostLinux::~ExtensionCrashHandlerHostLinux() { 416 ExtensionCrashHandlerHostPosix::~ExtensionCrashHandlerHostPosix() {
404 } 417 }
405 418
406 void ExtensionCrashHandlerHostLinux::SetProcessType() { 419 void ExtensionCrashHandlerHostPosix::SetProcessType() {
407 process_type_ = "extension"; 420 process_type_ = "extension";
408 } 421 }
409 422
410 // static 423 // static
411 ExtensionCrashHandlerHostLinux* ExtensionCrashHandlerHostLinux::GetInstance() { 424 ExtensionCrashHandlerHostPosix* ExtensionCrashHandlerHostPosix::GetInstance() {
412 return Singleton<ExtensionCrashHandlerHostLinux>::get(); 425 return Singleton<ExtensionCrashHandlerHostPosix>::get();
413 } 426 }
414 427
415 GpuCrashHandlerHostLinux::GpuCrashHandlerHostLinux() { 428 GpuCrashHandlerHostPosix::GpuCrashHandlerHostPosix() {
416 InitCrashUploaderThread(); 429 InitCrashUploaderThread();
417 } 430 }
418 431
419 GpuCrashHandlerHostLinux::~GpuCrashHandlerHostLinux() { 432 GpuCrashHandlerHostPosix::~GpuCrashHandlerHostPosix() {
420 } 433 }
421 434
422 void GpuCrashHandlerHostLinux::SetProcessType() { 435 void GpuCrashHandlerHostPosix::SetProcessType() {
423 process_type_ = "gpu-process"; 436 process_type_ = "gpu-process";
424 } 437 }
425 438
426 // static 439 // static
427 GpuCrashHandlerHostLinux* GpuCrashHandlerHostLinux::GetInstance() { 440 GpuCrashHandlerHostPosix* GpuCrashHandlerHostPosix::GetInstance() {
428 return Singleton<GpuCrashHandlerHostLinux>::get(); 441 return Singleton<GpuCrashHandlerHostPosix>::get();
429 } 442 }
430 443
431 PluginCrashHandlerHostLinux::PluginCrashHandlerHostLinux() { 444 PluginCrashHandlerHostPosix::PluginCrashHandlerHostPosix() {
432 InitCrashUploaderThread(); 445 InitCrashUploaderThread();
433 } 446 }
434 447
435 PluginCrashHandlerHostLinux::~PluginCrashHandlerHostLinux() { 448 PluginCrashHandlerHostPosix::~PluginCrashHandlerHostPosix() {
436 } 449 }
437 450
438 void PluginCrashHandlerHostLinux::SetProcessType() { 451 void PluginCrashHandlerHostPosix::SetProcessType() {
439 process_type_ = "plugin"; 452 process_type_ = "plugin";
440 } 453 }
441 454
442 // static 455 // static
443 PluginCrashHandlerHostLinux* PluginCrashHandlerHostLinux::GetInstance() { 456 PluginCrashHandlerHostPosix* PluginCrashHandlerHostPosix::GetInstance() {
444 return Singleton<PluginCrashHandlerHostLinux>::get(); 457 return Singleton<PluginCrashHandlerHostPosix>::get();
445 } 458 }
446 459
447 PpapiCrashHandlerHostLinux::PpapiCrashHandlerHostLinux() { 460 PpapiCrashHandlerHostPosix::PpapiCrashHandlerHostPosix() {
448 InitCrashUploaderThread(); 461 InitCrashUploaderThread();
449 } 462 }
450 463
451 PpapiCrashHandlerHostLinux::~PpapiCrashHandlerHostLinux() { 464 PpapiCrashHandlerHostPosix::~PpapiCrashHandlerHostPosix() {
452 } 465 }
453 466
454 void PpapiCrashHandlerHostLinux::SetProcessType() { 467 void PpapiCrashHandlerHostPosix::SetProcessType() {
455 process_type_ = "ppapi"; 468 process_type_ = "ppapi";
456 } 469 }
457 470
458 // static 471 // static
459 PpapiCrashHandlerHostLinux* PpapiCrashHandlerHostLinux::GetInstance() { 472 PpapiCrashHandlerHostPosix* PpapiCrashHandlerHostPosix::GetInstance() {
460 return Singleton<PpapiCrashHandlerHostLinux>::get(); 473 return Singleton<PpapiCrashHandlerHostPosix>::get();
461 } 474 }
462 475
463 RendererCrashHandlerHostLinux::RendererCrashHandlerHostLinux() { 476 RendererCrashHandlerHostPosix::RendererCrashHandlerHostPosix() {
464 InitCrashUploaderThread(); 477 InitCrashUploaderThread();
465 } 478 }
466 479
467 RendererCrashHandlerHostLinux::~RendererCrashHandlerHostLinux() { 480 RendererCrashHandlerHostPosix::~RendererCrashHandlerHostPosix() {
468 } 481 }
469 482
470 void RendererCrashHandlerHostLinux::SetProcessType() { 483 void RendererCrashHandlerHostPosix::SetProcessType() {
471 process_type_ = "renderer"; 484 process_type_ = "renderer";
472 } 485 }
473 486
474 // static 487 // static
475 RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() { 488 RendererCrashHandlerHostPosix* RendererCrashHandlerHostPosix::GetInstance() {
476 return Singleton<RendererCrashHandlerHostLinux>::get(); 489 return Singleton<RendererCrashHandlerHostPosix>::get();
477 } 490 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698