summaryrefslogtreecommitdiffstats
path: root/chrome/browser/nacl_host/nacl_process_host.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/nacl_host/nacl_process_host.cc')
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc229
1 files changed, 229 insertions, 0 deletions
diff --git a/chrome/browser/nacl_host/nacl_process_host.cc b/chrome/browser/nacl_host/nacl_process_host.cc
new file mode 100644
index 0000000..fb844d8
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_process_host.cc
@@ -0,0 +1,229 @@
+// 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 "build/build_config.h"
+
+#include "chrome/browser/nacl_host/nacl_process_host.h"
+
+#if defined(OS_POSIX)
+#include <fcntl.h>
+#endif
+
+#include "base/command_line.h"
+#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_cmd_line.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"
+#elif defined(OS_WIN)
+#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
+#endif
+
+NaClProcessHost::NaClProcessHost(
+ ResourceDispatcherHost *resource_dispatcher_host,
+ const std::wstring& url)
+ : BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host),
+ resource_dispatcher_host_(resource_dispatcher_host),
+ reply_msg_(NULL),
+ descriptor_(0),
+ running_on_wow64_(false) {
+ set_name(url);
+#if defined(OS_WIN)
+ CheckIsWow64();
+#endif
+}
+
+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);
+ nacl::CopyNaClCommandLineArguments(cmd_line);
+
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kNaClLoaderProcess);
+
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
+
+ // On Windows we might need to start the broker process to launch a new loader
+#if defined(OS_WIN)
+ if (running_on_wow64_) {
+ NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_);
+ return NaClBrokerService::GetInstance()->LaunchLoader(this,
+ ASCIIToWide(channel_id()));
+ } else {
+ BrowserChildProcessHost::Launch(FilePath(), cmd_line);
+ }
+#elif defined(OS_POSIX)
+ BrowserChildProcessHost::Launch(true, // use_zygote
+ base::environment_vector(),
+ cmd_line);
+#endif
+
+ return true;
+}
+
+void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) {
+ set_handle(handle);
+ OnProcessLaunched();
+}
+
+bool NaClProcessHost::DidChildCrash() {
+ if (running_on_wow64_)
+ return base::DidProcessCrash(NULL, handle());
+ return BrowserChildProcessHost::DidChildCrash();
+}
+
+void NaClProcessHost::OnChildDied() {
+#if defined(OS_WIN)
+ NaClBrokerService::GetInstance()->OnLoaderDied();
+#endif
+ BrowserChildProcessHost::OnChildDied();
+}
+
+void NaClProcessHost::OnProcessLaunched() {
+ nacl::FileDescriptor imc_handle;
+ base::ProcessHandle nacl_process_handle;
+#if defined(OS_WIN)
+ // Duplicate the IMC handle
+ // We assume the size of imc_handle has the same size as HANDLE, so the cast
+ // below is safe.
+ DCHECK(sizeof(HANDLE) == sizeof(imc_handle));
+ DuplicateHandle(base::GetCurrentProcessHandle(),
+ reinterpret_cast<HANDLE>(pair_[0]),
+ resource_message_filter_->handle(),
+ reinterpret_cast<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;
+}
+
+#if defined(OS_WIN)
+// TODO(gregoryd): invoke CheckIsWow64 only once, not for each NaClProcessHost
+typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
+void NaClProcessHost::CheckIsWow64() {
+ LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
+ GetModuleHandle(TEXT("kernel32")),
+ "IsWow64Process");
+
+ if (fnIsWow64Process != NULL) {
+ BOOL bIsWow64 = FALSE;
+ if (fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) {
+ if (bIsWow64) {
+ running_on_wow64_ = true;
+ }
+ }
+ }
+}
+#endif