summaryrefslogtreecommitdiffstats
path: root/chrome/browser/nacl_host
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-07-29 17:14:53 +0100
committerBen Murdoch <benm@google.com>2010-08-04 14:29:45 +0100
commitc407dc5cd9bdc5668497f21b26b09d988ab439de (patch)
tree7eaf8707c0309516bdb042ad976feedaf72b0bb1 /chrome/browser/nacl_host
parent0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff)
downloadexternal_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.zip
external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.gz
external_chromium-c407dc5cd9bdc5668497f21b26b09d988ab439de.tar.bz2
Merge Chromium src@r53293
Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
Diffstat (limited to 'chrome/browser/nacl_host')
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.cc76
-rw-r--r--chrome/browser/nacl_host/nacl_broker_host_win.h49
-rw-r--r--chrome/browser/nacl_host/nacl_broker_service_win.cc83
-rw-r--r--chrome/browser/nacl_host/nacl_broker_service_win.h57
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.cc229
-rw-r--r--chrome/browser/nacl_host/nacl_process_host.h83
6 files changed, 577 insertions, 0 deletions
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.cc b/chrome/browser/nacl_host/nacl_broker_host_win.cc
new file mode 100644
index 0000000..f479030
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.cc
@@ -0,0 +1,76 @@
+// 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/nacl_host/nacl_broker_host_win.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "ipc/ipc_switches.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/nacl_host/nacl_broker_service_win.h"
+#include "chrome/browser/nacl_host/nacl_process_host.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/nacl_cmd_line.h"
+#include "chrome/common/nacl_messages.h"
+
+NaClBrokerHost::NaClBrokerHost(
+ ResourceDispatcherHost* resource_dispatcher_host)
+ : BrowserChildProcessHost(NACL_BROKER_PROCESS, resource_dispatcher_host),
+ stopping_(false) {
+}
+
+NaClBrokerHost::~NaClBrokerHost() {
+}
+
+URLRequestContext* NaClBrokerHost::GetRequestContext(
+ uint32 request_id,
+ const ViewHostMsg_Resource_Request& request_data) {
+ return NULL;
+}
+
+bool NaClBrokerHost::Init() {
+ // Create the channel that will be used for communicating with the broker.
+ if (!CreateChannel())
+ return false;
+
+ // Create the path to the nacl broker/loader executable.
+ FilePath module_path;
+ if (!PathService::Get(base::FILE_MODULE, &module_path))
+ return false;
+
+ FilePath nacl_path = module_path.DirName().Append(chrome::kNaClAppName);
+ CommandLine* cmd_line = new CommandLine(nacl_path);
+ nacl::CopyNaClCommandLineArguments(cmd_line);
+
+ cmd_line->AppendSwitchWithValue(switches::kProcessType,
+ switches::kNaClBrokerProcess);
+
+ cmd_line->AppendSwitchWithValue(switches::kProcessChannelID,
+ ASCIIToWide(channel_id()));
+
+ BrowserChildProcessHost::Launch(FilePath(), cmd_line);
+ return true;
+}
+
+void NaClBrokerHost::OnMessageReceived(const IPC::Message& msg) {
+ IPC_BEGIN_MESSAGE_MAP(NaClBrokerHost, msg)
+ IPC_MESSAGE_HANDLER(NaClProcessMsg_LoaderLaunched, OnLoaderLaunched)
+ IPC_END_MESSAGE_MAP()
+}
+
+bool NaClBrokerHost::LaunchLoader(
+ const std::wstring& loader_channel_id) {
+ return Send(new NaClProcessMsg_LaunchLoaderThroughBroker(loader_channel_id));
+}
+
+void NaClBrokerHost::OnLoaderLaunched(const std::wstring& loader_channel_id,
+ base::ProcessHandle handle) {
+ NaClBrokerService::GetInstance()->OnLoaderLaunched(loader_channel_id, handle);
+}
+
+void NaClBrokerHost::StopBroker() {
+ stopping_ = true;
+ Send(new NaClProcessMsg_StopBroker());
+}
diff --git a/chrome/browser/nacl_host/nacl_broker_host_win.h b/chrome/browser/nacl_host/nacl_broker_host_win.h
new file mode 100644
index 0000000..8668328
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_broker_host_win.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_WIN_H_
+#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_WIN_H_
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "chrome/browser/browser_child_process_host.h"
+#include "ipc/ipc_message.h"
+
+class NaClBrokerHost : public BrowserChildProcessHost {
+ public:
+ explicit NaClBrokerHost(ResourceDispatcherHost* resource_dispatcher_host);
+ ~NaClBrokerHost();
+
+ // This function starts the broker process. It needs to be called
+ // before loaders can be launched.
+ bool Init();
+
+ // Send a message to the broker process, causing it to launch
+ // a Native Client loader process.
+ bool LaunchLoader(const std::wstring& loader_channel_id);
+
+ // Stop the broker process.
+ void StopBroker();
+
+ private:
+ // ResourceDispatcherHost::Receiver implementation:
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id,
+ const ViewHostMsg_Resource_Request& request_data);
+
+ virtual bool CanShutdown() { return true; }
+
+ // Handler for NaClProcessMsg_LoaderLaunched message
+ void OnLoaderLaunched(const std::wstring& loader_channel_id,
+ base::ProcessHandle handle);
+
+ // IPC::Channel::Listener
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ bool stopping_;
+
+ DISALLOW_COPY_AND_ASSIGN(NaClBrokerHost);
+};
+
+#endif // CHROME_BROWSER_NACL_HOST_NACL_BROKER_HOST_WIN_H_
diff --git a/chrome/browser/nacl_host/nacl_broker_service_win.cc b/chrome/browser/nacl_host/nacl_broker_service_win.cc
new file mode 100644
index 0000000..d5524ad
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_broker_service_win.cc
@@ -0,0 +1,83 @@
+// 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/nacl_host/nacl_broker_service_win.h"
+
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/nacl_host/nacl_process_host.h"
+#include "chrome/common/chrome_switches.h"
+
+NaClBrokerService* NaClBrokerService::GetInstance() {
+ return Singleton<NaClBrokerService>::get();
+}
+
+NaClBrokerService::NaClBrokerService()
+ : loaders_running_(0),
+ resource_dispatcher_host_(NULL),
+ initialized_(false) {
+}
+
+void NaClBrokerService::Init(ResourceDispatcherHost* resource_dispatcher_host) {
+ if (!initialized_)
+ resource_dispatcher_host_ = resource_dispatcher_host;
+ initialized_ = true;
+}
+
+bool NaClBrokerService::StartBroker() {
+ NaClBrokerHost* broker_host = new NaClBrokerHost(resource_dispatcher_host_);
+ if (!broker_host->Init()) {
+ delete broker_host;
+ return false;
+ }
+ return true;
+}
+
+bool NaClBrokerService::LaunchLoader(NaClProcessHost* nacl_process_host,
+ const std::wstring& loader_channel_id) {
+ // Add task to the list
+ pending_launches_[loader_channel_id] = nacl_process_host;
+ NaClBrokerHost* broker_host = GetBrokerHost();
+
+ if (!broker_host) {
+ if (!StartBroker())
+ return false;
+ broker_host = GetBrokerHost();
+ }
+ broker_host->LaunchLoader(loader_channel_id);
+
+ return true;
+}
+
+void NaClBrokerService::OnLoaderLaunched(const std::wstring& channel_id,
+ base::ProcessHandle handle) {
+ NaClProcessHost* client;
+ PendingLaunchesMap::iterator it = pending_launches_.find(channel_id);
+ if (pending_launches_.end() == it)
+ NOTREACHED();
+
+ client = it->second;
+ client->OnProcessLaunchedByBroker(handle);
+ pending_launches_.erase(it);
+ ++loaders_running_;
+}
+
+void NaClBrokerService::OnLoaderDied() {
+ --loaders_running_;
+ // Stop the broker only if there are no loaders running or being launched.
+ NaClBrokerHost* broker_host = GetBrokerHost();
+ if (loaders_running_ + pending_launches_.size() == 0 && broker_host != NULL) {
+ broker_host->StopBroker();
+ }
+}
+
+NaClBrokerHost* NaClBrokerService::GetBrokerHost() {
+ for (BrowserChildProcessHost::Iterator iter(
+ ChildProcessInfo::NACL_BROKER_PROCESS);
+ !iter.Done();
+ ++iter) {
+ NaClBrokerHost* broker_host = static_cast<NaClBrokerHost*>(*iter);
+ return broker_host;
+ }
+ return NULL;
+}
diff --git a/chrome/browser/nacl_host/nacl_broker_service_win.h b/chrome/browser/nacl_host/nacl_broker_service_win.h
new file mode 100644
index 0000000..cb5b4c0
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_broker_service_win.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_WIN_H_
+#define CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_WIN_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/singleton.h"
+#include "chrome/browser/nacl_host/nacl_broker_host_win.h"
+
+class NaClProcessHost;
+
+class NaClBrokerService {
+ public:
+ // Returns the NaClBrokerService singleton.
+ static NaClBrokerService* GetInstance();
+
+ void Init(ResourceDispatcherHost* resource_dispatcher_host);
+
+ // Can be called several times, must be called before LaunchLoader.
+ bool StartBroker();
+
+ // Send a message to the broker process, causing it to launch
+ // a Native Client loader process.
+ bool LaunchLoader(NaClProcessHost* client,
+ const std::wstring& loader_channel_id);
+
+ // Called by NaClBrokerHost to notify the service that a loader was launched.
+ void OnLoaderLaunched(const std::wstring& channel_id,
+ base::ProcessHandle handle);
+
+ // Called by NaClProcessHost when a loader process is terminated
+ void OnLoaderDied();
+
+ private:
+ typedef std::map<std::wstring, NaClProcessHost*>
+ PendingLaunchesMap;
+
+ friend struct DefaultSingletonTraits<NaClBrokerService>;
+
+ NaClBrokerService();
+ ~NaClBrokerService() {}
+
+ NaClBrokerHost* GetBrokerHost();
+
+ int loaders_running_;
+ bool initialized_;
+ ResourceDispatcherHost* resource_dispatcher_host_;
+ PendingLaunchesMap pending_launches_;
+
+ DISALLOW_COPY_AND_ASSIGN(NaClBrokerService);
+};
+
+#endif // CHROME_BROWSER_NACL_HOST_NACL_BROKER_SERVICE_WIN_H_
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
diff --git a/chrome/browser/nacl_host/nacl_process_host.h b/chrome/browser/nacl_host/nacl_process_host.h
new file mode 100644
index 0000000..cae117b
--- /dev/null
+++ b/chrome/browser/nacl_host/nacl_process_host.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef CHROME_BROWSER_NACL_HOST_NACL_PROCESS_HOST_H_
+#define CHROME_BROWSER_NACL_HOST_NACL_PROCESS_HOST_H_
+
+#include "build/build_config.h"
+
+#include "base/ref_counted.h"
+#include "chrome/browser/browser_child_process_host.h"
+#include "chrome/common/nacl_types.h"
+#include "native_client/src/shared/imc/nacl_imc.h"
+
+class ResourceMessageFilter;
+
+// Represents the browser side of the browser <--> NaCl communication
+// channel. There will be one NaClProcessHost per NaCl process
+// The browser is responsible for starting the NaCl process
+// when requested by the renderer.
+// After that, most of the communication is directly between NaCl plugin
+// running in the renderer and NaCl processes.
+class NaClProcessHost : public BrowserChildProcessHost {
+ public:
+ NaClProcessHost(ResourceDispatcherHost *resource_dispatcher_host,
+ const std::wstring& url);
+ ~NaClProcessHost();
+
+ // Initialize the new NaCl process, returning true on success.
+ bool Launch(ResourceMessageFilter* resource_message_filter,
+ const int descriptor,
+ IPC::Message* reply_msg);
+
+ virtual void OnMessageReceived(const IPC::Message& msg);
+
+ void OnProcessLaunchedByBroker(base::ProcessHandle handle);
+
+ protected:
+ virtual bool DidChildCrash();
+ virtual void OnChildDied();
+
+ private:
+ bool LaunchSelLdr();
+
+ void SendStartMessage();
+
+ virtual void OnProcessLaunched();
+
+ // ResourceDispatcherHost::Receiver implementation:
+ virtual URLRequestContext* GetRequestContext(
+ uint32 request_id,
+ const ViewHostMsg_Resource_Request& request_data);
+
+ virtual bool CanShutdown() { return true; }
+
+#if defined(OS_WIN)
+ // Check whether the browser process is running on WOW64 - Windows only
+ void CheckIsWow64();
+#endif
+
+ private:
+ ResourceDispatcherHost* resource_dispatcher_host_;
+
+ // The ResourceMessageFilter that requested this NaCl process. We use this
+ // for sending the reply once the process has started.
+ scoped_refptr<ResourceMessageFilter> resource_message_filter_;
+
+ // The reply message to send.
+ IPC::Message* reply_msg_;
+
+ // The socket pair for the NaCl process.
+ nacl::Handle pair_[2];
+
+ // The NaCl specific descriptor for this process.
+ int descriptor_;
+
+ // Windows platform flag
+ bool running_on_wow64_;
+
+ DISALLOW_COPY_AND_ASSIGN(NaClProcessHost);
+};
+
+#endif // CHROME_BROWSER_NACL_HOST_NACL_PROCESS_HOST_H_