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 "content/browser/browser_child_process_host_impl.h" | 5 #include "content/browser/browser_child_process_host_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
9 #include "base/file_path.h" | 9 #include "base/file_path.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 #include "content/common/plugin_messages.h" | 21 #include "content/common/plugin_messages.h" |
22 #include "content/public/browser/browser_thread.h" | 22 #include "content/public/browser/browser_thread.h" |
23 #include "content/public/browser/browser_child_process_host_delegate.h" | 23 #include "content/public/browser/browser_child_process_host_delegate.h" |
24 #include "content/public/browser/child_process_data.h" | 24 #include "content/public/browser/child_process_data.h" |
25 #include "content/public/browser/content_browser_client.h" | 25 #include "content/public/browser/content_browser_client.h" |
26 #include "content/public/browser/notification_service.h" | 26 #include "content/public/browser/notification_service.h" |
27 #include "content/public/browser/notification_types.h" | 27 #include "content/public/browser/notification_types.h" |
28 #include "content/public/common/content_switches.h" | 28 #include "content/public/common/content_switches.h" |
29 #include "content/public/common/result_codes.h" | 29 #include "content/public/common/result_codes.h" |
30 | 30 |
31 #if defined(OS_WIN) | 31 #if defined(OS_MACOSX) |
32 #include "base/synchronization/waitable_event.h" | |
33 #elif defined(OS_MACOSX) | |
34 #include "content/browser/mach_broker_mac.h" | 32 #include "content/browser/mach_broker_mac.h" |
35 #endif | 33 #endif |
36 | 34 |
37 using content::BrowserChildProcessHostDelegate; | 35 using content::BrowserChildProcessHostDelegate; |
38 using content::BrowserThread; | 36 using content::BrowserThread; |
39 using content::ChildProcessData; | 37 using content::ChildProcessData; |
40 using content::ChildProcessHost; | 38 using content::ChildProcessHost; |
41 using content::ChildProcessHostImpl; | 39 using content::ChildProcessHostImpl; |
42 | 40 |
43 namespace { | 41 namespace { |
(...skipping 30 matching lines...) Expand all Loading... |
74 | 72 |
75 BrowserChildProcessHostImpl::BrowserChildProcessList* | 73 BrowserChildProcessHostImpl::BrowserChildProcessList* |
76 BrowserChildProcessHostImpl::GetIterator() { | 74 BrowserChildProcessHostImpl::GetIterator() { |
77 return g_child_process_list.Pointer(); | 75 return g_child_process_list.Pointer(); |
78 } | 76 } |
79 | 77 |
80 BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( | 78 BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( |
81 content::ProcessType type, | 79 content::ProcessType type, |
82 BrowserChildProcessHostDelegate* delegate) | 80 BrowserChildProcessHostDelegate* delegate) |
83 : data_(type), | 81 : data_(type), |
84 delegate_(delegate), | 82 delegate_(delegate) { |
85 #if !defined(OS_WIN) | |
86 ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), | |
87 #endif | |
88 disconnect_was_alive_(false) { | |
89 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); | 83 data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
90 | 84 |
91 child_process_host_.reset(ChildProcessHost::Create(this)); | 85 child_process_host_.reset(ChildProcessHost::Create(this)); |
92 child_process_host_->AddFilter(new TraceMessageFilter); | 86 child_process_host_->AddFilter(new TraceMessageFilter); |
93 child_process_host_->AddFilter(new content::ProfilerMessageFilter(type)); | 87 child_process_host_->AddFilter(new content::ProfilerMessageFilter(type)); |
94 | 88 |
95 g_child_process_list.Get().push_back(this); | 89 g_child_process_list.Get().push_back(this); |
96 content::GetContentClient()->browser()->BrowserChildProcessHostCreated(this); | 90 content::GetContentClient()->browser()->BrowserChildProcessHostCreated(this); |
97 } | 91 } |
98 | 92 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
204 } | 198 } |
205 | 199 |
206 void BrowserChildProcessHostImpl::OnChannelError() { | 200 void BrowserChildProcessHostImpl::OnChannelError() { |
207 delegate_->OnChannelError(); | 201 delegate_->OnChannelError(); |
208 } | 202 } |
209 | 203 |
210 bool BrowserChildProcessHostImpl::CanShutdown() { | 204 bool BrowserChildProcessHostImpl::CanShutdown() { |
211 return delegate_->CanShutdown(); | 205 return delegate_->CanShutdown(); |
212 } | 206 } |
213 | 207 |
214 // Normally a ChildProcessHostDelegate deletes itself from this callback, but at | |
215 // this layer and below we need to have the final child process exit code to | |
216 // properly bucket crashes vs kills. On Windows we can do this if we wait until | |
217 // the process handle is signaled; on the rest of the platforms, we schedule a | |
218 // delayed task to wait for an exit code. However, this means that this method | |
219 // may be called twice: once from the actual channel error and once from | |
220 // OnWaitableEventSignaled() or the delayed task. | |
221 void BrowserChildProcessHostImpl::OnChildDisconnected() { | 208 void BrowserChildProcessHostImpl::OnChildDisconnected() { |
222 DCHECK(data_.handle != base::kNullProcessHandle); | 209 DCHECK(data_.handle != base::kNullProcessHandle); |
223 int exit_code; | 210 int exit_code; |
224 base::TerminationStatus status = GetTerminationStatus(&exit_code); | 211 base::TerminationStatus status = GetTerminationStatus(&exit_code); |
225 switch (status) { | 212 switch (status) { |
226 case base::TERMINATION_STATUS_PROCESS_CRASHED: | 213 case base::TERMINATION_STATUS_PROCESS_CRASHED: |
227 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { | 214 case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { |
228 delegate_->OnProcessCrashed(exit_code); | 215 delegate_->OnProcessCrashed(exit_code); |
229 // Report that this child process crashed. | 216 // Report that this child process crashed. |
230 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); | 217 Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); |
231 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", | 218 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", |
232 data_.type, | 219 data_.type, |
233 content::PROCESS_TYPE_MAX); | 220 content::PROCESS_TYPE_MAX); |
234 if (disconnect_was_alive_) { | |
235 UMA_HISTOGRAM_ENUMERATION("ChildProcess.CrashedWasAlive", | |
236 data_.type, | |
237 content::PROCESS_TYPE_MAX); | |
238 } | |
239 break; | 221 break; |
240 } | 222 } |
241 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { | 223 case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { |
242 delegate_->OnProcessCrashed(exit_code); | 224 delegate_->OnProcessCrashed(exit_code); |
243 // Report that this child process was killed. | 225 // Report that this child process was killed. |
244 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed", | 226 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed", |
245 data_.type, | 227 data_.type, |
246 content::PROCESS_TYPE_MAX); | 228 content::PROCESS_TYPE_MAX); |
247 if (disconnect_was_alive_) { | |
248 UMA_HISTOGRAM_ENUMERATION("ChildProcess.KilledWasAlive", | |
249 data_.type, | |
250 content::PROCESS_TYPE_MAX); | |
251 } | |
252 break; | 229 break; |
253 } | 230 } |
254 case base::TERMINATION_STATUS_STILL_RUNNING: { | 231 case base::TERMINATION_STATUS_STILL_RUNNING: { |
255 // Exit code not yet available. Ensure we don't wait forever for an exit | 232 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive", |
256 // code. | 233 data_.type, |
257 if (disconnect_was_alive_) { | 234 content::PROCESS_TYPE_MAX); |
258 UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive", | |
259 data_.type, | |
260 content::PROCESS_TYPE_MAX); | |
261 break; | |
262 } | |
263 disconnect_was_alive_ = true; | |
264 #if defined(OS_WIN) | |
265 child_watcher_.StartWatching( | |
266 new base::WaitableEvent(data_.handle), this); | |
267 #else | |
268 // On non-Windows platforms, give the child process some time to die after | |
269 // disconnecting the channel so that the exit code and termination status | |
270 // become available. This is best effort -- if the process doesn't die | |
271 // within the time limit, this object gets destroyed. | |
272 const base::TimeDelta kExitCodeWait = | |
273 base::TimeDelta::FromMilliseconds(250); | |
274 MessageLoop::current()->PostDelayedTask( | |
275 FROM_HERE, | |
276 base::Bind(&BrowserChildProcessHostImpl::OnChildDisconnected, | |
277 task_factory_.GetWeakPtr()), | |
278 kExitCodeWait); | |
279 #endif | |
280 return; | |
281 } | 235 } |
282 | |
283 default: | 236 default: |
284 break; | 237 break; |
285 } | 238 } |
286 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", | 239 UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", |
287 data_.type, | 240 data_.type, |
288 content::PROCESS_TYPE_MAX); | 241 content::PROCESS_TYPE_MAX); |
289 // Notify in the main loop of the disconnection. | 242 // Notify in the main loop of the disconnection. |
290 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); | 243 Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); |
291 delete delegate_; // Will delete us | 244 delete delegate_; // Will delete us |
292 } | 245 } |
293 | 246 |
294 // The child process handle has been signaled so the exit code is finally | |
295 // available. Unfortunately STILL_ACTIVE (0x103) is a valid exit code in | |
296 // which case we should not call OnChildDisconnected() or else we will be | |
297 // waiting forever. | |
298 void BrowserChildProcessHostImpl::OnWaitableEventSignaled( | |
299 base::WaitableEvent* waitable_event) { | |
300 #if defined (OS_WIN) | |
301 unsigned long exit_code = 0; | |
302 GetExitCodeProcess(waitable_event->Release(), &exit_code); | |
303 delete waitable_event; | |
304 if (exit_code == STILL_ACTIVE) { | |
305 delete delegate_; // Will delete us | |
306 } else { | |
307 BrowserChildProcessHostImpl::OnChildDisconnected(); | |
308 } | |
309 #endif | |
310 } | |
311 | |
312 bool BrowserChildProcessHostImpl::Send(IPC::Message* message) { | 247 bool BrowserChildProcessHostImpl::Send(IPC::Message* message) { |
313 return child_process_host_->Send(message); | 248 return child_process_host_->Send(message); |
314 } | 249 } |
315 | 250 |
316 void BrowserChildProcessHostImpl::OnProcessLaunched() { | 251 void BrowserChildProcessHostImpl::OnProcessLaunched() { |
317 if (!child_process_->GetHandle()) { | 252 if (!child_process_->GetHandle()) { |
318 delete delegate_; // Will delete us | 253 delete delegate_; // Will delete us |
319 return; | 254 return; |
320 } | 255 } |
321 data_.handle = child_process_->GetHandle(); | 256 data_.handle = child_process_->GetHandle(); |
322 delegate_->OnProcessLaunched(); | 257 delegate_->OnProcessLaunched(); |
323 } | 258 } |
OLD | NEW |