michael@0: // Copyright (c) 2009 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "chrome/common/child_thread.h" michael@0: michael@0: #include "base/string_util.h" michael@0: #include "base/command_line.h" michael@0: #include "chrome/common/child_process.h" michael@0: #include "chrome/common/chrome_switches.h" michael@0: #include "chrome/common/ipc_logging.h" michael@0: michael@0: // V8 needs a 1MB stack size. michael@0: const size_t ChildThread::kV8StackSize = 1024 * 1024; michael@0: michael@0: ChildThread::ChildThread(Thread::Options options) michael@0: : Thread("Chrome_ChildThread"), michael@0: owner_loop_(MessageLoop::current()), michael@0: options_(options), michael@0: check_with_browser_before_shutdown_(false) { michael@0: DCHECK(owner_loop_); michael@0: channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue( michael@0: switches::kProcessChannelID); michael@0: } michael@0: michael@0: ChildThread::~ChildThread() { michael@0: } michael@0: michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: #include "ipc/Nuwa.h" michael@0: #endif michael@0: michael@0: bool ChildThread::Run() { michael@0: bool r = StartWithOptions(options_); michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: NS_ASSERTION(NuwaMarkCurrentThread, "NuwaMarkCurrentThread is not defined!"); michael@0: if (IsNuwaProcess()) { michael@0: message_loop()->PostTask(FROM_HERE, michael@0: NewRunnableFunction(&ChildThread::MarkThread)); michael@0: } michael@0: #endif michael@0: return r; michael@0: } michael@0: michael@0: void ChildThread::OnChannelError() { michael@0: owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); michael@0: } michael@0: michael@0: #ifdef MOZ_NUWA_PROCESS michael@0: void ChildThread::MarkThread() { michael@0: NuwaMarkCurrentThread(nullptr, nullptr); michael@0: if (!NuwaCheckpointCurrentThread()) { michael@0: NS_RUNTIMEABORT("Should not be here!"); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: bool ChildThread::Send(IPC::Message* msg) { michael@0: if (!channel_.get()) { michael@0: delete msg; michael@0: return false; michael@0: } michael@0: michael@0: return channel_->Send(msg); michael@0: } michael@0: michael@0: void ChildThread::AddRoute(int32_t routing_id, IPC::Channel::Listener* listener) { michael@0: DCHECK(MessageLoop::current() == message_loop()); michael@0: michael@0: router_.AddRoute(routing_id, listener); michael@0: } michael@0: michael@0: void ChildThread::RemoveRoute(int32_t routing_id) { michael@0: DCHECK(MessageLoop::current() == message_loop()); michael@0: michael@0: router_.RemoveRoute(routing_id); michael@0: } michael@0: michael@0: void ChildThread::OnMessageReceived(const IPC::Message& msg) { michael@0: if (msg.routing_id() == MSG_ROUTING_CONTROL) { michael@0: OnControlMessageReceived(msg); michael@0: } else { michael@0: router_.OnMessageReceived(msg); michael@0: } michael@0: } michael@0: michael@0: ChildThread* ChildThread::current() { michael@0: return ChildProcess::current()->child_thread(); michael@0: } michael@0: michael@0: void ChildThread::Init() { michael@0: channel_.reset(new IPC::Channel(channel_name_, michael@0: IPC::Channel::MODE_CLIENT, michael@0: this)); michael@0: michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: IPC::Logging::current()->SetIPCSender(this); michael@0: #endif michael@0: } michael@0: michael@0: void ChildThread::CleanUp() { michael@0: #ifdef IPC_MESSAGE_LOG_ENABLED michael@0: IPC::Logging::current()->SetIPCSender(NULL); michael@0: #endif michael@0: // Need to destruct the SyncChannel to the browser before we go away because michael@0: // it caches a pointer to this thread. michael@0: channel_.reset(); michael@0: } michael@0: michael@0: void ChildThread::OnProcessFinalRelease() { michael@0: if (!check_with_browser_before_shutdown_) { michael@0: owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); michael@0: return; michael@0: } michael@0: }