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