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

Side by Side Diff: components/crash/content/browser/crash_micro_dump_manager_android.cc

Issue 1525023003: Distinguish in the browser between renderer crashes and kills (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Finalized, RFC Created 5 years 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 2015 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 #include "components/crash/content/browser/crash_micro_dump_manager_android.h"
6
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include "base/bind.h"
14 #include "base/files/scoped_file.h"
15 #include "base/logging.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "base/stl_util.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/child_process_data.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/notification_types.h"
22 #include "content/public/browser/render_process_host.h"
23
24 using content::BrowserThread;
25
26 namespace breakpad {
27
28 // static
29 CrashMicroDumpManager* CrashMicroDumpManager::instance_ = nullptr;
30
31 // static
32 CrashMicroDumpManager* CrashMicroDumpManager::GetInstance() {
33 CHECK(instance_);
34 return instance_;
35 }
36
37 CrashMicroDumpManager::CrashMicroDumpManager() {
38 DCHECK_CURRENTLY_ON(BrowserThread::UI);
39 DCHECK(!instance_);
40
41 instance_ = this;
42
43 notification_registrar_.Add(this,
44 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
45 content::NotificationService::AllSources());
46 notification_registrar_.Add(this,
47 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
48 content::NotificationService::AllSources());
49 BrowserChildProcessObserver::Add(this);
50 }
51
52 CrashMicroDumpManager::~CrashMicroDumpManager() {
53 instance_ = nullptr;
54 BrowserChildProcessObserver::Remove(this);
55 {
56 base::AutoLock auto_lock(child_process_id_to_pipe_fd_lock_);
57 for (const auto& iter : child_process_id_to_pipe_fd_) {
58 IGNORE_EINTR(close(iter.second));
59 }
60 }
61 }
62
63 bool SocketPair(int* fd1, int* fd2) {
Torne 2015/12/16 14:48:35 Don't we have a utility somewhere that does this?
mnaganov (inactive) 2015/12/16 19:10:12 It's good you've asked! I initially copied this co
64 int pipe_fds[2];
65 if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
66 PLOG(ERROR) << "socketpair()";
67 return false;
68 }
69
70 // Set both ends to be non-blocking.
71 if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
72 fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
73 PLOG(ERROR) << "fcntl(O_NONBLOCK)";
74 if (IGNORE_EINTR(close(pipe_fds[0])) < 0)
75 PLOG(ERROR) << "close";
76 if (IGNORE_EINTR(close(pipe_fds[1])) < 0)
77 PLOG(ERROR) << "close";
78 return false;
79 }
80
81 *fd1 = pipe_fds[0];
82 *fd2 = pipe_fds[1];
83
84 return true;
85 }
86
87 base::File CrashMicroDumpManager::CreateCrashInfoChannel(int child_process_id) {
88 DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
89 int local_pipe_fd = -1, child_pipe_fd = -1;
90 if (!SocketPair(&local_pipe_fd, &child_pipe_fd)) {
91 return base::File();
92 }
93 {
94 base::AutoLock auto_lock(child_process_id_to_pipe_fd_lock_);
95 DCHECK(!ContainsKey(child_process_id_to_pipe_fd_, child_process_id));
96 child_process_id_to_pipe_fd_[child_process_id] = local_pipe_fd;
97 }
98 return base::File(child_pipe_fd);
99 }
100
101 // static
102 void CrashMicroDumpManager::HandleChildTermination(int pipe_fd) {
103 DCHECK_CURRENTLY_ON(BrowserThread::FILE);
104 CHECK(instance_);
105
106 base::ScopedFD pipe(pipe_fd);
107 int exit_code;
108 ssize_t num_read = HANDLE_EINTR(read(pipe_fd, &exit_code, sizeof(exit_code)));
109 if (num_read <= 0) {
110 // The child process hasn't written anything into the pipe. Assuming
111 // that it didn't crash, thus we need to perform a clean exit.
112 exit(0);
113 } else {
114 LOG(FATAL) << "Renderer process crash detected. Terminating browser.";
115 }
116 }
117
118 void CrashMicroDumpManager::BrowserChildProcessHostDisconnected(
119 const content::ChildProcessData& data) {
120 OnChildExit(data.id);
121 }
122
123 void CrashMicroDumpManager::BrowserChildProcessCrashed(
124 const content::ChildProcessData& data,
125 int exit_code) {
126 OnChildExit(data.id);
127 }
128
129 void CrashMicroDumpManager::Observe(
130 int type,
131 const content::NotificationSource& source,
132 const content::NotificationDetails& details) {
133 content::RenderProcessHost* rph =
134 content::Source<content::RenderProcessHost>(source).ptr();
135 OnChildExit(rph->GetID());
136 }
137
138 void CrashMicroDumpManager::OnChildExit(int child_process_id) {
139 int pipe_fd = -1;
140 {
141 base::AutoLock auto_lock(child_process_id_to_pipe_fd_lock_);
142 const auto& iter = child_process_id_to_pipe_fd_.find(child_process_id);
143 if (iter == child_process_id_to_pipe_fd_.end()) {
144 // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
145 // NOTIFICATION_RENDERER_PROCESS_CLOSED.
146 return;
147 }
148 pipe_fd = iter->second;
149 child_process_id_to_pipe_fd_.erase(iter);
150 }
151 DCHECK(pipe_fd != -1);
152 BrowserThread::PostTask(
153 BrowserThread::FILE, FROM_HERE,
154 base::Bind(&CrashMicroDumpManager::HandleChildTermination, pipe_fd));
155 }
156
157 } // namespace breakpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698