| Index: base/mp/mp_child_thread.cc
|
| ===================================================================
|
| --- base/mp/mp_child_thread.cc (revision 0)
|
| +++ base/mp/mp_child_thread.cc (revision 0)
|
| @@ -0,0 +1,153 @@
|
| +// 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_thread.h"
|
| +
|
| +#include "base/string_util.h"
|
| +#include "base/command_line.h"
|
| +#include "base/mp/mp_child_process.h"
|
| +#include "base/mp/mp_messages.h"
|
| +#include "ipc/ipc_logging.h"
|
| +#include "ipc/ipc_message.h"
|
| +#include "ipc/ipc_sync_message_filter.h"
|
| +#include "ipc/ipc_switches.h"
|
| +
|
| +namespace base {
|
| +
|
| +MpChildThread::MpChildThread() {
|
| + channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
|
| + switches::kProcessChannelID);
|
| + Init();
|
| +}
|
| +
|
| +MpChildThread::MpChildThread(const std::string& channel_name)
|
| + : channel_name_(channel_name) {
|
| + Init();
|
| +}
|
| +
|
| +void MpChildThread::Init() {
|
| + check_with_parent_before_shutdown_ = false;
|
| + on_channel_error_called_ = false;
|
| + message_loop_ = MessageLoop::current();
|
| +
|
| + channel_.reset(new IPC::SyncChannel(channel_name_,
|
| + IPC::Channel::MODE_CLIENT, this, NULL,
|
| + MpChildProcess::current()->io_message_loop(), true,
|
| + MpChildProcess::current()->GetShutDownEvent()));
|
| +#ifdef IPC_MESSAGE_LOG_ENABLED
|
| + IPC::Logging::current()->SetIPCSender(this);
|
| +#endif
|
| +
|
| + sync_message_filter_ =
|
| + new IPC::SyncMessageFilter(MpChildProcess::current()->GetShutDownEvent());
|
| + channel_->AddFilter(sync_message_filter_.get());
|
| +}
|
| +
|
| +MpChildThread::~MpChildThread() {
|
| +#ifdef IPC_MESSAGE_LOG_ENABLED
|
| + IPC::Logging::current()->SetIPCSender(NULL);
|
| +#endif
|
| +
|
| + channel_->RemoveFilter(sync_message_filter_.get());
|
| +
|
| + // The ChannelProxy object caches a pointer to the IPC thread, so need to
|
| + // reset it as it's not guaranteed to outlive this object.
|
| + // NOTE: this also has the side-effect of not closing the main IPC channel to
|
| + // the browser process. This is needed because this is the signal that the
|
| + // browser uses to know that this process has died, so we need it to be alive
|
| + // until this process is shut down, and the OS closes the handle
|
| + // automatically. We used to watch the object handle on Windows to do this,
|
| + // but it wasn't possible to do so on POSIX.
|
| + channel_->ClearIPCMessageLoop();
|
| +}
|
| +
|
| +void MpChildThread::OnChannelError() {
|
| + set_on_channel_error_called(true);
|
| + MessageLoop::current()->Quit();
|
| +}
|
| +
|
| +bool MpChildThread::Send(IPC::Message* msg) {
|
| + if (!channel_.get()) {
|
| + delete msg;
|
| + return false;
|
| + }
|
| +
|
| + return channel_->Send(msg);
|
| +}
|
| +
|
| +void MpChildThread::AddRoute(int32 routing_id, IPC::Channel::Listener* listener) {
|
| + DCHECK(MessageLoop::current() == message_loop());
|
| +
|
| + router_.AddRoute(routing_id, listener);
|
| +}
|
| +
|
| +void MpChildThread::RemoveRoute(int32 routing_id) {
|
| + DCHECK(MessageLoop::current() == message_loop());
|
| +
|
| + router_.RemoveRoute(routing_id);
|
| +}
|
| +
|
| +IPC::Channel::Listener* MpChildThread::ResolveRoute(int32 routing_id) {
|
| + DCHECK(MessageLoop::current() == message_loop());
|
| +
|
| + return router_.ResolveRoute(routing_id);
|
| +}
|
| +
|
| +void MpChildThread::OnMessageReceived(const IPC::Message& msg) {
|
| + bool handled = true;
|
| + IPC_BEGIN_MESSAGE_MAP(MpChildThread, msg)
|
| + IPC_MESSAGE_HANDLER(MultiProcessMsg_AskBeforeShutdown, OnAskBeforeShutdown)
|
| + IPC_MESSAGE_HANDLER(MultiProcessMsg_Shutdown, OnShutdown)
|
| +#if defined(IPC_MESSAGE_LOG_ENABLED)
|
| + IPC_MESSAGE_HANDLER(MultiProcessMsg_SetIPCLoggingEnabled,
|
| + OnSetIPCLoggingEnabled)
|
| +#endif
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP()
|
| +
|
| + if (handled)
|
| + return;
|
| +
|
| + if (msg.routing_id() == MSG_ROUTING_CONTROL) {
|
| + OnControlMessageReceived(msg);
|
| + } else {
|
| + router_.OnMessageReceived(msg);
|
| + }
|
| +}
|
| +
|
| +void MpChildThread::OnAskBeforeShutdown() {
|
| + check_with_parent_before_shutdown_ = true;
|
| +}
|
| +
|
| +void MpChildThread::OnShutdown() {
|
| + MessageLoop::current()->Quit();
|
| +}
|
| +
|
| +#if defined(IPC_MESSAGE_LOG_ENABLED)
|
| +void MpChildThread::OnSetIPCLoggingEnabled(bool enable) {
|
| + if (enable)
|
| + IPC::Logging::current()->Enable();
|
| + else
|
| + IPC::Logging::current()->Disable();
|
| +}
|
| +#endif // IPC_MESSAGE_LOG_ENABLED
|
| +
|
| +MpChildThread* MpChildThread::current() {
|
| + return MpChildProcess::current()->main_thread();
|
| +}
|
| +
|
| +void MpChildThread::OnProcessFinalRelease() {
|
| + if (on_channel_error_called_ || !check_with_parent_before_shutdown_) {
|
| + MessageLoop::current()->Quit();
|
| + return;
|
| + }
|
| +
|
| + // The child process shutdown sequence is a request response based mechanism,
|
| + // where we send out an initial feeler request to the child process host
|
| + // instance in the browser to verify if it's ok to shutdown the child process.
|
| + // The browser then sends back a response if it's ok to shutdown.
|
| + Send(new MultiProcessHostMsg_ShutdownRequest);
|
| +}
|
| +
|
| +} // namespace base
|
|
|