Index: content/browser/browser_child_process_host.cc |
=================================================================== |
--- content/browser/browser_child_process_host.cc (revision 118727) |
+++ content/browser/browser_child_process_host.cc (working copy) |
@@ -1,317 +0,0 @@ |
-// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "content/browser/browser_child_process_host.h" |
- |
-#include "base/bind.h" |
-#include "base/command_line.h" |
-#include "base/file_path.h" |
-#include "base/lazy_instance.h" |
-#include "base/logging.h" |
-#include "base/metrics/histogram.h" |
-#include "base/path_service.h" |
-#include "base/process_util.h" |
-#include "base/stl_util.h" |
-#include "base/string_util.h" |
-#include "content/browser/profiler_message_filter.h" |
-#include "content/browser/renderer_host/resource_message_filter.h" |
-#include "content/browser/trace_message_filter.h" |
-#include "content/common/child_process_host_impl.h" |
-#include "content/common/plugin_messages.h" |
-#include "content/public/browser/browser_thread.h" |
-#include "content/public/browser/browser_child_process_host_delegate.h" |
-#include "content/public/browser/child_process_data.h" |
-#include "content/public/browser/content_browser_client.h" |
-#include "content/public/browser/notification_service.h" |
-#include "content/public/browser/notification_types.h" |
-#include "content/public/common/content_switches.h" |
-#include "content/public/common/result_codes.h" |
- |
-#if defined(OS_WIN) |
-#include "base/synchronization/waitable_event.h" |
-#else |
-#include "base/bind.h" |
-#endif |
- |
-using content::BrowserChildProcessHostDelegate; |
-using content::BrowserThread; |
-using content::ChildProcessData; |
-using content::ChildProcessHost; |
-using content::ChildProcessHostImpl; |
- |
-namespace { |
- |
-static base::LazyInstance<BrowserChildProcessHost::BrowserChildProcessList> |
- g_child_process_list = LAZY_INSTANCE_INITIALIZER; |
- |
-// Helper functions since the child process related notifications happen on the |
-// UI thread. |
-void ChildNotificationHelper(int notification_type, |
- const ChildProcessData& data) { |
- content::NotificationService::current()-> |
- Notify(notification_type, content::NotificationService::AllSources(), |
- content::Details<const ChildProcessData>(&data)); |
-} |
- |
-} // namespace |
- |
-namespace content { |
- |
-BrowserChildProcessHost* BrowserChildProcessHost::Create( |
- ProcessType type, |
- BrowserChildProcessHostDelegate* delegate) { |
- return new ::BrowserChildProcessHost(type, delegate); |
-} |
- |
-} // namespace content |
- |
-BrowserChildProcessHost::BrowserChildProcessList* |
- BrowserChildProcessHost::GetIterator() { |
- return g_child_process_list.Pointer(); |
-} |
- |
-BrowserChildProcessHost::BrowserChildProcessHost( |
- content::ProcessType type, |
- BrowserChildProcessHostDelegate* delegate) |
- : data_(type), |
- delegate_(delegate), |
-#if !defined(OS_WIN) |
- ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)), |
-#endif |
- disconnect_was_alive_(false) { |
- data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId(); |
- |
- child_process_host_.reset(ChildProcessHost::Create(this)); |
- child_process_host_->AddFilter(new TraceMessageFilter); |
- child_process_host_->AddFilter(new ProfilerMessageFilter); |
- |
- g_child_process_list.Get().push_back(this); |
-} |
- |
-BrowserChildProcessHost::~BrowserChildProcessHost() { |
- g_child_process_list.Get().remove(this); |
-} |
- |
-// static |
-void BrowserChildProcessHost::TerminateAll() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- // Make a copy since the BrowserChildProcessHost dtor mutates the original |
- // list. |
- BrowserChildProcessList copy = g_child_process_list.Get(); |
- STLDeleteElements(©); |
-} |
- |
-void BrowserChildProcessHost::Launch( |
-#if defined(OS_WIN) |
- const FilePath& exposed_dir, |
-#elif defined(OS_POSIX) |
- bool use_zygote, |
- const base::environment_vector& environ, |
-#endif |
- CommandLine* cmd_line) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- |
- content::GetContentClient()->browser()->AppendExtraCommandLineSwitches( |
- cmd_line, data_.id); |
- |
- child_process_.reset(new ChildProcessLauncher( |
-#if defined(OS_WIN) |
- exposed_dir, |
-#elif defined(OS_POSIX) |
- use_zygote, |
- environ, |
- child_process_host_->TakeClientFileDescriptor(), |
-#endif |
- cmd_line, |
- this)); |
-} |
- |
-const ChildProcessData& BrowserChildProcessHost::GetData() const { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- return data_; |
-} |
- |
-ChildProcessHost* BrowserChildProcessHost::GetHost() const { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- return child_process_host_.get(); |
-} |
- |
-base::ProcessHandle BrowserChildProcessHost::GetHandle() const { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- DCHECK(child_process_.get()) |
- << "Requesting a child process handle before launching."; |
- DCHECK(child_process_->GetHandle()) |
- << "Requesting a child process handle before launch has completed OK."; |
- return child_process_->GetHandle(); |
-} |
- |
-void BrowserChildProcessHost::SetName(const string16& name) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- data_.name = name; |
-} |
- |
-void BrowserChildProcessHost::SetHandle(base::ProcessHandle handle) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- data_.handle = handle; |
-} |
- |
-void BrowserChildProcessHost::ForceShutdown() { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- g_child_process_list.Get().remove(this); |
- child_process_host_->ForceShutdown(); |
-} |
- |
-void BrowserChildProcessHost::SetTerminateChildOnShutdown( |
- bool terminate_on_shutdown) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- child_process_->SetTerminateChildOnShutdown(terminate_on_shutdown); |
-} |
- |
-void BrowserChildProcessHost::Notify(int type) { |
- BrowserThread::PostTask( |
- BrowserThread::UI, |
- FROM_HERE, |
- base::Bind(&ChildNotificationHelper, type, data_)); |
-} |
- |
-base::TerminationStatus BrowserChildProcessHost::GetTerminationStatus( |
- int* exit_code) { |
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
- if (!child_process_.get()) // If the delegate doesn't use Launch() helper. |
- return base::GetTerminationStatus(data_.handle, exit_code); |
- return child_process_->GetChildTerminationStatus(exit_code); |
-} |
- |
-bool BrowserChildProcessHost::OnMessageReceived(const IPC::Message& message) { |
- return delegate_->OnMessageReceived(message); |
-} |
- |
-void BrowserChildProcessHost::OnChannelConnected(int32 peer_pid) { |
- Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_CONNECTED); |
- delegate_->OnChannelConnected(peer_pid); |
-} |
- |
-void BrowserChildProcessHost::OnChannelError() { |
- delegate_->OnChannelError(); |
-} |
- |
-bool BrowserChildProcessHost::CanShutdown() { |
- return delegate_->CanShutdown(); |
-} |
- |
-// Normally a ChildProcessHostDelegate deletes itself from this callback, but at |
-// this layer and below we need to have the final child process exit code to |
-// properly bucket crashes vs kills. On Windows we can do this if we wait until |
-// the process handle is signaled; on the rest of the platforms, we schedule a |
-// delayed task to wait for an exit code. However, this means that this method |
-// may be called twice: once from the actual channel error and once from |
-// OnWaitableEventSignaled() or the delayed task. |
-void BrowserChildProcessHost::OnChildDisconnected() { |
- DCHECK(data_.handle != base::kNullProcessHandle); |
- int exit_code; |
- base::TerminationStatus status = GetTerminationStatus(&exit_code); |
- switch (status) { |
- case base::TERMINATION_STATUS_PROCESS_CRASHED: |
- case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: { |
- delegate_->OnProcessCrashed(exit_code); |
- // Report that this child process crashed. |
- Notify(content::NOTIFICATION_CHILD_PROCESS_CRASHED); |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- if (disconnect_was_alive_) { |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.CrashedWasAlive", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- } |
- break; |
- } |
- case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: { |
- // Report that this child process was killed. |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- if (disconnect_was_alive_) { |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.KilledWasAlive", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- } |
- break; |
- } |
- case base::TERMINATION_STATUS_STILL_RUNNING: { |
- // Exit code not yet available. Ensure we don't wait forever for an exit |
- // code. |
- if (disconnect_was_alive_) { |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- break; |
- } |
- disconnect_was_alive_ = true; |
-#if defined(OS_WIN) |
- child_watcher_.StartWatching( |
- new base::WaitableEvent(data_.handle), this); |
-#else |
- // On non-Windows platforms, give the child process some time to die after |
- // disconnecting the channel so that the exit code and termination status |
- // become available. This is best effort -- if the process doesn't die |
- // within the time limit, this object gets destroyed. |
- const int kExitCodeWaitMs = 250; |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&BrowserChildProcessHost::OnChildDisconnected, |
- task_factory_.GetWeakPtr()), |
- kExitCodeWaitMs); |
-#endif |
- return; |
- } |
- |
- default: |
- break; |
- } |
- UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected", |
- data_.type, |
- content::PROCESS_TYPE_MAX); |
- // Notify in the main loop of the disconnection. |
- Notify(content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED); |
- delete delegate_; // Will delete us |
-} |
- |
-// The child process handle has been signaled so the exit code is finally |
-// available. Unfortunately STILL_ACTIVE (0x103) is a valid exit code in |
-// which case we should not call OnChildDisconnected() or else we will be |
-// waiting forever. |
-void BrowserChildProcessHost::OnWaitableEventSignaled( |
- base::WaitableEvent* waitable_event) { |
-#if defined (OS_WIN) |
- unsigned long exit_code = 0; |
- GetExitCodeProcess(waitable_event->Release(), &exit_code); |
- delete waitable_event; |
- if (exit_code == STILL_ACTIVE) { |
- delete delegate_; // Will delete us |
- } else { |
- BrowserChildProcessHost::OnChildDisconnected(); |
- } |
-#endif |
-} |
- |
-bool BrowserChildProcessHost::Send(IPC::Message* message) { |
- return child_process_host_->Send(message); |
-} |
- |
-void BrowserChildProcessHost::ShutdownStarted() { |
- // Must remove the process from the list now, in case it gets used for a |
- // new instance before our watcher tells us that the process terminated. |
- g_child_process_list.Get().remove(this); |
-} |
- |
- |
-void BrowserChildProcessHost::OnProcessLaunched() { |
- if (!child_process_->GetHandle()) { |
- delete delegate_; // Will delete us |
- return; |
- } |
- data_.handle = child_process_->GetHandle(); |
- delegate_->OnProcessLaunched(); |
-} |