Index: base/mp/mp_child_process_host.cc |
=================================================================== |
--- base/mp/mp_child_process_host.cc (revision 0) |
+++ base/mp/mp_child_process_host.cc (revision 0) |
@@ -0,0 +1,190 @@ |
+// Copyright (c) 2010 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 "base/mp/mp_child_process_host.h" |
+ |
+#include "base/command_line.h" |
+#include "base/compiler_specific.h" |
+#include "base/file_path.h" |
+#include "base/histogram.h" |
+#include "base/logging.h" |
+#include "base/mp/mp_child_process_context.h" |
+#include "base/mp/mp_messages.h" |
+#include "base/path_service.h" |
+#include "base/process_util.h" |
+#include "base/singleton.h" |
+#include "base/string_util.h" |
+#include "base/waitable_event.h" |
+ |
+#if defined(OS_LINUX) |
+#include "base/linux_util.h" |
+#endif // OS_LINUX |
+ |
+ |
+namespace base { |
+ |
+namespace { |
+ |
+typedef std::list<MpChildProcessHost*> ChildProcessList; |
+ |
+} // namespace |
+ |
+MpChildProcessHost::MpChildProcessHost(MpChildProcessContext* context) |
+ : ALLOW_THIS_IN_INITIALIZER_LIST(listener_(this)), |
+ context_(context), |
+ opening_channel_(false) { |
+ Singleton<ChildProcessList>::get()->push_back(this); |
+} |
+ |
+ |
+MpChildProcessHost::~MpChildProcessHost() { |
+ Singleton<ChildProcessList>::get()->remove(this); |
+} |
+ |
+void MpChildProcessHost::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) { |
+ child_process_.reset(new MpChildProcessLauncher( |
+#if defined(OS_WIN) |
+ exposed_dir, |
+#elif defined(OS_POSIX) |
+ use_zygote, |
+ environ, |
+ channel_->GetClientFileDescriptor(), |
+#endif |
+ cmd_line, |
+ context_, |
+ &listener_)); |
+} |
+ |
+bool MpChildProcessHost::CreateChannel() { |
+ channel_id_ = context_->GenerateRandomChannelID(this); |
+ channel_.reset(new IPC::Channel( |
+ channel_id_, IPC::Channel::MODE_SERVER, &listener_)); |
+ if (!channel_->Connect()) |
+ return false; |
+ |
+ opening_channel_ = true; |
+ |
+ return true; |
+} |
+ |
+void MpChildProcessHost::InstanceCreated() { |
+ Notify(CHILD_INSTANCE_CREATED); |
+} |
+ |
+bool MpChildProcessHost::Send(IPC::Message* msg) { |
+ if (!channel_.get()) { |
+ delete msg; |
+ return false; |
+ } |
+ return channel_->Send(msg); |
+} |
+ |
+bool MpChildProcessHost::DidChildCrash() { |
+ return child_process_->DidProcessCrash(); |
+} |
+ |
+void MpChildProcessHost::OnChildDied() { |
+ if (GetHandle() != base::kNullProcessHandle) { |
+ bool did_crash = DidChildCrash(); |
+ if (did_crash) { |
+ OnProcessCrashed(); |
+ // Report that this child process crashed. |
+ Notify(CHILD_PROCESS_CRASHED); |
+ UMA_HISTOGRAM_COUNTS("ChildProcess.Crashes", GetType()); |
+ } |
+ // Notify in the main loop of the disconnection. |
+ Notify(CHILD_PROCESS_HOST_DISCONNECTED); |
+ } |
+ |
+ delete this; |
+} |
+ |
+MpChildProcessHost::ListenerHook::ListenerHook(MpChildProcessHost* host) |
+ : host_(host) { |
+} |
+ |
+void MpChildProcessHost::ListenerHook::OnMessageReceived( |
+ const IPC::Message& msg) { |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ IPC::Logging* logger = IPC::Logging::current(); |
+ if (msg.type() == IPC_LOGGING_ID) { |
+ logger->OnReceivedLoggingMessage(msg); |
+ return; |
+ } |
+ |
+ if (logger->Enabled()) |
+ logger->OnPreDispatchMessage(msg); |
+#endif |
+ |
+ bool msg_is_ok = true; |
+ bool handled = host_->OnDispatchMessageReceived(msg, &msg_is_ok); |
+ |
+ if (!handled) { |
+ if (msg.type() == MultiProcessHostMsg_ShutdownRequest::ID) { |
+ // 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. |
+ Singleton<ChildProcessList>::get()->remove(host_); |
+ if (host_->CanShutdown()) |
+ host_->Send(new MultiProcessMsg_Shutdown()); |
+ } else { |
+ host_->OnMessageReceived(msg); |
+ } |
+ } |
+ |
+ if (!msg_is_ok) { |
+ base::KillProcess(host_->GetHandle(), |
+ host_->context_->GetBadMessageResultCode(), false); |
+ } |
+ |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ if (logger->Enabled()) |
+ logger->OnPostDispatchMessage(msg, host_->channel_id_); |
+#endif |
+} |
+ |
+void MpChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) { |
+ host_->opening_channel_ = false; |
+ host_->OnChannelConnected(peer_pid); |
+ |
+#if defined(IPC_MESSAGE_LOG_ENABLED) |
+ bool enabled = IPC::Logging::current()->Enabled(); |
+ host_->Send(new MultiProcessMsg_SetIPCLoggingEnabled(enabled)); |
+#endif |
+ |
+ host_->Send(new MultiProcessMsg_AskBeforeShutdown()); |
+ |
+ // Notify in the main loop of the connection. |
+ host_->Notify(CHILD_PROCESS_HOST_CONNECTED); |
+} |
+ |
+void MpChildProcessHost::ListenerHook::OnChannelError() { |
+ host_->opening_channel_ = false; |
+ host_->OnChannelError(); |
+ |
+ // This will delete host_, which will also destroy this! |
+ host_->OnChildDied(); |
+} |
+ |
+void MpChildProcessHost::ListenerHook::OnProcessLaunched() { |
+ if (!host_->child_process_->GetHandle()) { |
+ delete this; |
+ return; |
+ } |
+ |
+ host_->OnProcessLaunched(); |
+} |
+ |
+void MpChildProcessHost::ForceShutdown() { |
+ Singleton<ChildProcessList>::get()->remove(this); |
+ Send(new MultiProcessMsg_Shutdown()); |
+} |
+ |
+} // namespace base |