| 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 |