// Copyright (c) 2009 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 "build/build_config.h" #include "chrome/browser/nacl_process_host.h" #if defined(OS_POSIX) #include #endif #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/logging_chrome.h" #include "chrome/common/nacl_messages.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_switches.h" #if defined(OS_POSIX) #include "ipc/ipc_channel_posix.h" #endif NaClProcessHost::NaClProcessHost( ResourceDispatcherHost *resource_dispatcher_host, const std::wstring& url) : ChildProcessHost(NACL_PROCESS, resource_dispatcher_host), resource_dispatcher_host_(resource_dispatcher_host), reply_msg_(NULL), descriptor_(0) { set_name(url); } NaClProcessHost::~NaClProcessHost() { if (!reply_msg_) return; // OnProcessLaunched didn't get called because the process couldn't launch. // Don't keep the renderer hanging. reply_msg_->set_reply_error(); resource_message_filter_->Send(reply_msg_); } bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter, const int descriptor, IPC::Message* reply_msg) { #ifdef DISABLE_NACL NOTIMPLEMENTED() << "Native Client disabled at build time"; return false; #else // Create a connected socket if (nacl::SocketPair(pair_) == -1) return false; // Launch the process descriptor_ = descriptor; if (!LaunchSelLdr()) { nacl::Close(pair_[0]); return false; } resource_message_filter_ = resource_message_filter; reply_msg_ = reply_msg; return true; #endif // DISABLE_NACL } bool NaClProcessHost::LaunchSelLdr() { if (!CreateChannel()) return false; // Build command line for nacl. FilePath exe_path = GetChildPath(); if (exe_path.empty()) return false; CommandLine* cmd_line = new CommandLine(exe_path); if (logging::DialogsAreSuppressed()) cmd_line->AppendSwitch(switches::kNoErrorDialogs); // Propagate the following switches to the plugin command line (along with // any associated values) if present in the browser command line. // TODO(gregoryd): check which flags of those below can be supported. static const char* const switch_names[] = { switches::kNoSandbox, switches::kTestSandbox, switches::kDisableBreakpad, switches::kFullMemoryCrashReport, switches::kEnableLogging, switches::kDisableLogging, switches::kLoggingLevel, switches::kEnableDCHECK, switches::kSilentDumpOnDCHECK, switches::kMemoryProfiling, }; const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess(); for (size_t i = 0; i < arraysize(switch_names); ++i) { if (browser_command_line.HasSwitch(switch_names[i])) { cmd_line->AppendSwitchWithValue( switch_names[i], browser_command_line.GetSwitchValueASCII(switch_names[i])); } } cmd_line->AppendSwitchWithValue(switches::kProcessType, switches::kNaClProcess); cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, ASCIIToWide(channel_id())); ChildProcessHost::Launch( #if defined(OS_WIN) FilePath(), #elif defined(OS_POSIX) base::environment_vector(), #endif cmd_line); return true; } void NaClProcessHost::OnProcessLaunched() { nacl::FileDescriptor imc_handle; base::ProcessHandle nacl_process_handle; #if NACL_WINDOWS // Duplicate the IMC handle DuplicateHandle(base::GetCurrentProcessHandle(), reinterpret_cast(pair_[0]), resource_message_filter_->handle(), &imc_handle, GENERIC_READ | GENERIC_WRITE, FALSE, DUPLICATE_CLOSE_SOURCE); // Duplicate the process handle DuplicateHandle(base::GetCurrentProcessHandle(), handle(), resource_message_filter_->handle(), &nacl_process_handle, PROCESS_DUP_HANDLE, FALSE, 0); #else int flags = fcntl(pair_[0], F_GETFD); if (flags != -1) { flags |= FD_CLOEXEC; fcntl(pair_[0], F_SETFD, flags); } // No need to dup the imc_handle - we don't pass it anywhere else so // it cannot be closed. imc_handle.fd = pair_[0]; imc_handle.auto_close = true; // We use pid as process handle on Posix nacl_process_handle = handle(); #endif // Get the pid of the NaCl process base::ProcessId nacl_process_id = base::GetProcId(handle()); ViewHostMsg_LaunchNaCl::WriteReplyParams( reply_msg_, imc_handle, nacl_process_handle, nacl_process_id); resource_message_filter_->Send(reply_msg_); resource_message_filter_ = NULL; reply_msg_ = NULL; SendStartMessage(); } void NaClProcessHost::SendStartMessage() { nacl::FileDescriptor channel; #if defined(OS_WIN) if (!DuplicateHandle(GetCurrentProcess(), reinterpret_cast(pair_[1]), handle(), reinterpret_cast(&channel), GENERIC_READ | GENERIC_WRITE, FALSE, DUPLICATE_CLOSE_SOURCE)) { return; } #else channel.fd = dup(pair_[1]); channel.auto_close = true; #endif Send(new NaClProcessMsg_Start(descriptor_, channel)); } void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { NOTREACHED() << "Invalid message with type = " << msg.type(); } URLRequestContext* NaClProcessHost::GetRequestContext( uint32 request_id, const ViewHostMsg_Resource_Request& request_data) { return NULL; }