nacl_process_host.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "build/build_config.h" 6 7#include "chrome/browser/nacl_host/nacl_process_host.h" 8 9#if defined(OS_POSIX) 10#include <fcntl.h> 11#endif 12 13#include "base/command_line.h" 14#include "chrome/browser/renderer_host/resource_message_filter.h" 15#include "chrome/common/chrome_switches.h" 16#include "chrome/common/logging_chrome.h" 17#include "chrome/common/nacl_cmd_line.h" 18#include "chrome/common/nacl_messages.h" 19#include "chrome/common/render_messages.h" 20#include "ipc/ipc_switches.h" 21 22#if defined(OS_POSIX) 23#include "ipc/ipc_channel_posix.h" 24#elif defined(OS_WIN) 25#include "chrome/browser/nacl_host/nacl_broker_service_win.h" 26#endif 27 28NaClProcessHost::NaClProcessHost( 29 ResourceDispatcherHost *resource_dispatcher_host, 30 const std::wstring& url) 31 : BrowserChildProcessHost(NACL_LOADER_PROCESS, resource_dispatcher_host), 32 resource_dispatcher_host_(resource_dispatcher_host), 33 reply_msg_(NULL), 34 descriptor_(0), 35 running_on_wow64_(false) { 36 set_name(url); 37#if defined(OS_WIN) 38 CheckIsWow64(); 39#endif 40} 41 42NaClProcessHost::~NaClProcessHost() { 43 if (!reply_msg_) 44 return; 45 46 // OnProcessLaunched didn't get called because the process couldn't launch. 47 // Don't keep the renderer hanging. 48 reply_msg_->set_reply_error(); 49 resource_message_filter_->Send(reply_msg_); 50} 51 52bool NaClProcessHost::Launch(ResourceMessageFilter* resource_message_filter, 53 const int descriptor, 54 IPC::Message* reply_msg) { 55#ifdef DISABLE_NACL 56 NOTIMPLEMENTED() << "Native Client disabled at build time"; 57 return false; 58#else 59 // Create a connected socket 60 if (nacl::SocketPair(pair_) == -1) 61 return false; 62 63 // Launch the process 64 descriptor_ = descriptor; 65 if (!LaunchSelLdr()) { 66 nacl::Close(pair_[0]); 67 return false; 68 } 69 70 resource_message_filter_ = resource_message_filter; 71 reply_msg_ = reply_msg; 72 73 return true; 74#endif // DISABLE_NACL 75} 76 77bool NaClProcessHost::LaunchSelLdr() { 78 if (!CreateChannel()) 79 return false; 80 81 // Build command line for nacl. 82 FilePath exe_path = GetChildPath(true); 83 if (exe_path.empty()) 84 return false; 85 86 CommandLine* cmd_line = new CommandLine(exe_path); 87 nacl::CopyNaClCommandLineArguments(cmd_line); 88 89 cmd_line->AppendSwitchWithValue(switches::kProcessType, 90 switches::kNaClLoaderProcess); 91 92 cmd_line->AppendSwitchWithValue(switches::kProcessChannelID, 93 ASCIIToWide(channel_id())); 94 95 // On Windows we might need to start the broker process to launch a new loader 96#if defined(OS_WIN) 97 if (running_on_wow64_) { 98 NaClBrokerService::GetInstance()->Init(resource_dispatcher_host_); 99 return NaClBrokerService::GetInstance()->LaunchLoader(this, 100 ASCIIToWide(channel_id())); 101 } else { 102 BrowserChildProcessHost::Launch(FilePath(), cmd_line); 103 } 104#elif defined(OS_POSIX) 105 BrowserChildProcessHost::Launch(true, // use_zygote 106 base::environment_vector(), 107 cmd_line); 108#endif 109 110 return true; 111} 112 113void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { 114 set_handle(handle); 115 OnProcessLaunched(); 116} 117 118bool NaClProcessHost::DidChildCrash() { 119 if (running_on_wow64_) 120 return base::DidProcessCrash(NULL, handle()); 121 return BrowserChildProcessHost::DidChildCrash(); 122} 123 124void NaClProcessHost::OnChildDied() { 125#if defined(OS_WIN) 126 NaClBrokerService::GetInstance()->OnLoaderDied(); 127#endif 128 BrowserChildProcessHost::OnChildDied(); 129} 130 131void NaClProcessHost::OnProcessLaunched() { 132 nacl::FileDescriptor imc_handle; 133 base::ProcessHandle nacl_process_handle; 134#if defined(OS_WIN) 135 // Duplicate the IMC handle 136 // We assume the size of imc_handle has the same size as HANDLE, so the cast 137 // below is safe. 138 DCHECK(sizeof(HANDLE) == sizeof(imc_handle)); 139 DuplicateHandle(base::GetCurrentProcessHandle(), 140 reinterpret_cast<HANDLE>(pair_[0]), 141 resource_message_filter_->handle(), 142 reinterpret_cast<HANDLE*>(&imc_handle), 143 GENERIC_READ | GENERIC_WRITE, 144 FALSE, 145 DUPLICATE_CLOSE_SOURCE); 146 147 // Duplicate the process handle 148 DuplicateHandle(base::GetCurrentProcessHandle(), 149 handle(), 150 resource_message_filter_->handle(), 151 &nacl_process_handle, 152 PROCESS_DUP_HANDLE, 153 FALSE, 154 0); 155#else 156 int flags = fcntl(pair_[0], F_GETFD); 157 if (flags != -1) { 158 flags |= FD_CLOEXEC; 159 fcntl(pair_[0], F_SETFD, flags); 160 } 161 // No need to dup the imc_handle - we don't pass it anywhere else so 162 // it cannot be closed. 163 imc_handle.fd = pair_[0]; 164 imc_handle.auto_close = true; 165 166 // We use pid as process handle on Posix 167 nacl_process_handle = handle(); 168#endif 169 170 // Get the pid of the NaCl process 171 base::ProcessId nacl_process_id = base::GetProcId(handle()); 172 173 ViewHostMsg_LaunchNaCl::WriteReplyParams( 174 reply_msg_, imc_handle, nacl_process_handle, nacl_process_id); 175 resource_message_filter_->Send(reply_msg_); 176 resource_message_filter_ = NULL; 177 reply_msg_ = NULL; 178 179 SendStartMessage(); 180} 181 182void NaClProcessHost::SendStartMessage() { 183 nacl::FileDescriptor channel; 184#if defined(OS_WIN) 185 if (!DuplicateHandle(GetCurrentProcess(), 186 reinterpret_cast<HANDLE>(pair_[1]), 187 handle(), 188 reinterpret_cast<HANDLE*>(&channel), 189 GENERIC_READ | GENERIC_WRITE, 190 FALSE, DUPLICATE_CLOSE_SOURCE)) { 191 return; 192 } 193#else 194 channel.fd = dup(pair_[1]); 195 channel.auto_close = true; 196#endif 197 Send(new NaClProcessMsg_Start(descriptor_, channel)); 198} 199 200void NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { 201 NOTREACHED() << "Invalid message with type = " << msg.type(); 202} 203 204URLRequestContext* NaClProcessHost::GetRequestContext( 205 uint32 request_id, 206 const ViewHostMsg_Resource_Request& request_data) { 207 return NULL; 208} 209 210#if defined(OS_WIN) 211// TODO(gregoryd): invoke CheckIsWow64 only once, not for each NaClProcessHost 212typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); 213void NaClProcessHost::CheckIsWow64() { 214 LPFN_ISWOW64PROCESS fnIsWow64Process; 215 216 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress( 217 GetModuleHandle(TEXT("kernel32")), 218 "IsWow64Process"); 219 220 if (fnIsWow64Process != NULL) { 221 BOOL bIsWow64 = FALSE; 222 if (fnIsWow64Process(GetCurrentProcess(),&bIsWow64)) { 223 if (bIsWow64) { 224 running_on_wow64_ = true; 225 } 226 } 227 } 228} 229#endif 230