// 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 "chrome/browser/gpu_process_host.h" #include "base/command_line.h" #include "base/singleton.h" #include "base/thread.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/child_process_host.h" #include "chrome/browser/child_process_launcher.h" #include "chrome/browser/io_thread.h" #include "chrome/common/child_process_info.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/gpu_messages.h" #include "ipc/ipc_switches.h" GpuProcessHost::GpuProcessHost() : last_routing_id_(1) { const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); std::wstring gpu_launcher = browser_command_line.GetSwitchValue(switches::kGpuLauncher); FilePath exe_path = ChildProcessHost::GetChildPath(gpu_launcher.empty()); if (exe_path.empty()) return; std::string channel_id = ChildProcessInfo::GenerateRandomChannelID(this); channel_.reset(new IPC::ChannelProxy( channel_id, IPC::Channel::MODE_SERVER, this, NULL, // No filter (for now). g_browser_process->io_thread()->message_loop())); CommandLine* cmd_line = new CommandLine(exe_path); cmd_line->AppendSwitchWithValue(switches::kProcessType, switches::kGpuProcess); cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, ASCIIToWide(channel_id)); // If specified, prepend a launcher program to the command line. if (!gpu_launcher.empty()) cmd_line->PrependWrapper(gpu_launcher); // Spawn the child process asynchronously to avoid blocking the UI thread. child_process_.reset(new ChildProcessLauncher( #if defined(OS_WIN) FilePath(), #elif defined(POSIX) false, // Never use the zygote (GPU plugin can't be sandboxed). base::environment_vector(), channel_->GetClientFileDescriptor(), #endif cmd_line, this)); } GpuProcessHost::~GpuProcessHost() { } // static GpuProcessHost* GpuProcessHost::Get() { GpuProcessHost* host = Singleton::get(); if (!host->child_process_.get()) return NULL; // Failed to init. return host; } int32 GpuProcessHost::GetNextRoutingId() { return ++last_routing_id_; } int32 GpuProcessHost::NewRenderWidgetHostView(GpuNativeWindowHandle parent) { int32 routing_id = GetNextRoutingId(); Send(new GpuMsg_NewRenderWidgetHostView(parent, routing_id)); return routing_id; } bool GpuProcessHost::Send(IPC::Message* msg) { if (!channel_.get()) { delete msg; return false; } if (child_process_.get() && child_process_->IsStarting()) { queued_messages_.push(msg); return true; } return channel_->Send(msg); } void GpuProcessHost::OnMessageReceived(const IPC::Message& message) { if (message.routing_id() == MSG_ROUTING_CONTROL) { // We don't currently have any control messages. // OnControlMessageReceived(message); } else { router_.OnMessageReceived(message); } } void GpuProcessHost::OnChannelConnected(int32 peer_pid) { } void GpuProcessHost::OnChannelError() { } void GpuProcessHost::OnProcessLaunched() { while (!queued_messages_.empty()) { Send(queued_messages_.front()); queued_messages_.pop(); } } void GpuProcessHost::AddRoute(int32 routing_id, IPC::Channel::Listener* listener) { router_.AddRoute(routing_id, listener); } void GpuProcessHost::RemoveRoute(int32 routing_id) { router_.RemoveRoute(routing_id); }