diff options
author | Ben Murdoch <benm@google.com> | 2010-07-29 17:14:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-04 14:29:45 +0100 |
commit | c407dc5cd9bdc5668497f21b26b09d988ab439de (patch) | |
tree | 7eaf8707c0309516bdb042ad976feedaf72b0bb1 /chrome/browser/nacl_host | |
parent | 0998b1cdac5733f299c12d88bc31ef9c8035b8fa (diff) | |
download | external_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.cc | 76 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_broker_host_win.h | 49 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_broker_service_win.cc | 83 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_broker_service_win.h | 57 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_process_host.cc | 229 | ||||
-rw-r--r-- | chrome/browser/nacl_host/nacl_process_host.h | 83 |
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_ |