blob: f736ab7332979a46ccdaca5b23251c171dc08da2 [file] [log] [blame]
// 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 <fcntl.h>
#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(true);
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,
#if defined(OS_MACOSX)
// TODO(dspringer): remove this when NaCl x86-32 security issues are fixed
switches::kEnableNaClOnMac,
#endif
};
const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
#if defined(OS_MACOSX)
// TODO(dspringer): NaCl is temporalrily disabled on the Mac by default, but it
// can be enabled with the --enable-nacl cmd-line switch. Remove this check
// when the security issues in the Mac PIC code are resolved.
if (!browser_command_line.HasSwitch(switches::kEnableNaClOnMac))
return false;
#endif
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)
false,
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<HANDLE>(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<HANDLE>(pair_[1]),
handle(),
reinterpret_cast<HANDLE*>(&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;
}