Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: remoting/host/win/unprivileged_process_delegate.cc

Issue 15077010: [Chromoting] Refactored worker process launching code and speeded up the desktop process launch. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 1
2 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be 3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file. 4 // found in the LICENSE file.
5 // 5 //
6 // This file implements the Windows service controlling Me2Me host processes 6 // This file implements the Windows service controlling Me2Me host processes
7 // running within user sessions. 7 // running within user sessions.
8 8
9 #include "remoting/host/win/unprivileged_process_delegate.h" 9 #include "remoting/host/win/unprivileged_process_delegate.h"
10 10
11 #include <sddl.h> 11 #include <sddl.h>
12 12
13 #include "base/command_line.h" 13 #include "base/command_line.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/process_util.h" 15 #include "base/process_util.h"
16 #include "base/rand_util.h" 16 #include "base/rand_util.h"
17 #include "base/single_thread_task_runner.h" 17 #include "base/single_thread_task_runner.h"
18 #include "base/string16.h" 18 #include "base/string16.h"
19 #include "base/stringprintf.h" 19 #include "base/stringprintf.h"
20 #include "base/synchronization/lock.h" 20 #include "base/synchronization/lock.h"
21 #include "base/utf_string_conversions.h" 21 #include "base/utf_string_conversions.h"
22 #include "base/win/scoped_handle.h" 22 #include "base/win/scoped_handle.h"
23 #include "base/win/windows_version.h" 23 #include "base/win/windows_version.h"
24 #include "ipc/ipc_channel.h" 24 #include "ipc/ipc_channel.h"
25 #include "ipc/ipc_channel_proxy.h" 25 #include "ipc/ipc_channel_proxy.h"
26 #include "ipc/ipc_message.h" 26 #include "ipc/ipc_message.h"
27 #include "remoting/base/typed_buffer.h" 27 #include "remoting/base/typed_buffer.h"
28 #include "remoting/host/host_exit_codes.h"
29 #include "remoting/host/ipc_constants.h" 28 #include "remoting/host/ipc_constants.h"
30 #include "remoting/host/win/launch_process_with_token.h" 29 #include "remoting/host/win/launch_process_with_token.h"
31 #include "remoting/host/win/security_descriptor.h" 30 #include "remoting/host/win/security_descriptor.h"
32 #include "remoting/host/win/window_station_and_desktop.h" 31 #include "remoting/host/win/window_station_and_desktop.h"
33 #include "sandbox/win/src/restricted_token.h" 32 #include "sandbox/win/src/restricted_token.h"
34 33
35 using base::win::ScopedHandle; 34 using base::win::ScopedHandle;
36 35
37 namespace remoting { 36 namespace remoting {
38 37
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 return false; 206 return false;
208 } 207 }
209 208
210 handles.Swap(*handles_out); 209 handles.Swap(*handles_out);
211 return true; 210 return true;
212 } 211 }
213 212
214 } // namespace 213 } // namespace
215 214
216 UnprivilegedProcessDelegate::UnprivilegedProcessDelegate( 215 UnprivilegedProcessDelegate::UnprivilegedProcessDelegate(
217 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
218 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, 216 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
219 scoped_ptr<CommandLine> target_command) 217 scoped_ptr<CommandLine> target_command)
220 : main_task_runner_(main_task_runner), 218 : io_task_runner_(io_task_runner),
221 io_task_runner_(io_task_runner), 219 event_handler_(NULL),
222 target_command_(target_command.Pass()) { 220 target_command_(target_command.Pass()) {
223 } 221 }
224 222
225 UnprivilegedProcessDelegate::~UnprivilegedProcessDelegate() { 223 UnprivilegedProcessDelegate::~UnprivilegedProcessDelegate() {
226 KillProcess(CONTROL_C_EXIT); 224 DCHECK(CalledOnValidThread());
225 DCHECK(!channel_);
226 DCHECK(!worker_process_.IsValid());
227 } 227 }
228 228
229 bool UnprivilegedProcessDelegate::Send(IPC::Message* message) { 229 void UnprivilegedProcessDelegate::LaunchProcess(
230 DCHECK(main_task_runner_->BelongsToCurrentThread()); 230 WorkerProcessLauncher* event_handler) {
231 DCHECK(CalledOnValidThread());
232 DCHECK(!event_handler_);
231 233
232 return channel_->Send(message); 234 event_handler_ = event_handler;
233 }
234
235 void UnprivilegedProcessDelegate::CloseChannel() {
236 DCHECK(main_task_runner_->BelongsToCurrentThread());
237
238 channel_.reset();
239 }
240
241 DWORD UnprivilegedProcessDelegate::GetProcessId() const {
242 if (worker_process_.IsValid()) {
243 return ::GetProcessId(worker_process_);
244 } else {
245 return 0;
246 }
247 }
248
249 bool UnprivilegedProcessDelegate::IsPermanentError(int failure_count) const {
250 // Get exit code of the worker process if it is available.
251 DWORD exit_code = CONTROL_C_EXIT;
252 if (worker_process_.IsValid()) {
253 if (!::GetExitCodeProcess(worker_process_, &exit_code)) {
254 LOG_GETLASTERROR(INFO)
255 << "Failed to query the exit code of the worker process";
256 exit_code = CONTROL_C_EXIT;
257 }
258 }
259
260 // Stop trying to restart the worker process if it exited due to
261 // misconfiguration.
262 return (kMinPermanentErrorExitCode <= exit_code &&
263 exit_code <= kMaxPermanentErrorExitCode);
264 }
265
266 void UnprivilegedProcessDelegate::KillProcess(DWORD exit_code) {
267 DCHECK(main_task_runner_->BelongsToCurrentThread());
268
269 channel_.reset();
270
271 if (worker_process_.IsValid()) {
272 TerminateProcess(worker_process_, exit_code);
273 }
274 }
275
276 bool UnprivilegedProcessDelegate::LaunchProcess(
277 IPC::Listener* delegate,
278 ScopedHandle* process_exit_event_out) {
279 DCHECK(main_task_runner_->BelongsToCurrentThread());
280 235
281 scoped_ptr<IPC::ChannelProxy> server; 236 scoped_ptr<IPC::ChannelProxy> server;
282 237
283 // Generate a unique name for the channel. 238 // Generate a unique name for the channel.
284 std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID(); 239 std::string channel_name = IPC::Channel::GenerateUniqueRandomChannelID();
285 240
286 // Create a restricted token that will be used to run the worker process. 241 // Create a restricted token that will be used to run the worker process.
287 ScopedHandle token; 242 ScopedHandle token;
288 if (!CreateRestrictedToken(&token)) { 243 if (!CreateRestrictedToken(&token)) {
289 LOG_GETLASTERROR(ERROR) 244 LOG_GETLASTERROR(ERROR)
290 << "Failed to create a restricted LocalService token"; 245 << "Failed to create a restricted LocalService token";
291 return false; 246 ReportFatalError();
247 return;
292 } 248 }
293 249
294 // Determine our logon SID, so we can grant it access to our window station 250 // Determine our logon SID, so we can grant it access to our window station
295 // and desktop. 251 // and desktop.
296 ScopedSid logon_sid = GetLogonSid(token); 252 ScopedSid logon_sid = GetLogonSid(token);
297 if (!logon_sid) { 253 if (!logon_sid) {
298 LOG_GETLASTERROR(ERROR) << "Failed to retrieve the logon SID"; 254 LOG_GETLASTERROR(ERROR) << "Failed to retrieve the logon SID";
299 return false; 255 ReportFatalError();
256 return;
300 } 257 }
301 258
302 // Create the process and thread security descriptors. 259 // Create the process and thread security descriptors.
303 ScopedSd process_sd = ConvertSddlToSd(kWorkerProcessSd); 260 ScopedSd process_sd = ConvertSddlToSd(kWorkerProcessSd);
304 ScopedSd thread_sd = ConvertSddlToSd(kWorkerThreadSd); 261 ScopedSd thread_sd = ConvertSddlToSd(kWorkerThreadSd);
305 if (!process_sd || !thread_sd) { 262 if (!process_sd || !thread_sd) {
306 LOG_GETLASTERROR(ERROR) << "Failed to create a security descriptor"; 263 LOG_GETLASTERROR(ERROR) << "Failed to create a security descriptor";
307 return false; 264 ReportFatalError();
265 return;
308 } 266 }
309 267
310 SECURITY_ATTRIBUTES process_attributes; 268 SECURITY_ATTRIBUTES process_attributes;
311 process_attributes.nLength = sizeof(process_attributes); 269 process_attributes.nLength = sizeof(process_attributes);
312 process_attributes.lpSecurityDescriptor = process_sd.get(); 270 process_attributes.lpSecurityDescriptor = process_sd.get();
313 process_attributes.bInheritHandle = FALSE; 271 process_attributes.bInheritHandle = FALSE;
314 272
315 SECURITY_ATTRIBUTES thread_attributes; 273 SECURITY_ATTRIBUTES thread_attributes;
316 thread_attributes.nLength = sizeof(thread_attributes); 274 thread_attributes.nLength = sizeof(thread_attributes);
317 thread_attributes.lpSecurityDescriptor = thread_sd.get(); 275 thread_attributes.lpSecurityDescriptor = thread_sd.get();
318 thread_attributes.bInheritHandle = FALSE; 276 thread_attributes.bInheritHandle = FALSE;
319 277
278 ScopedHandle worker_process;
320 { 279 {
321 // Take a lock why any inheritable handles are open to make sure that only 280 // Take a lock why any inheritable handles are open to make sure that only
322 // one process inherits them. 281 // one process inherits them.
323 base::AutoLock lock(g_inherit_handles_lock.Get()); 282 base::AutoLock lock(g_inherit_handles_lock.Get());
324 283
325 // Create a connected IPC channel. 284 // Create a connected IPC channel.
326 ScopedHandle client; 285 ScopedHandle client;
327 if (!CreateConnectedIpcChannel(channel_name, kDaemonIpcSd, io_task_runner_, 286 if (!CreateConnectedIpcChannel(channel_name, kDaemonIpcSd, io_task_runner_,
328 delegate, &client, &server)) { 287 this, &client, &server)) {
329 return false; 288 ReportFatalError();
289 return;
330 } 290 }
331 291
332 // Convert the handle value into a decimal integer. Handle values are 32bit 292 // Convert the handle value into a decimal integer. Handle values are 32bit
333 // even on 64bit platforms. 293 // even on 64bit platforms.
334 std::string pipe_handle = base::StringPrintf( 294 std::string pipe_handle = base::StringPrintf(
335 "%d", reinterpret_cast<ULONG_PTR>(client.Get())); 295 "%d", reinterpret_cast<ULONG_PTR>(client.Get()));
336 296
337 // Pass the IPC channel via the command line. 297 // Pass the IPC channel via the command line.
338 CommandLine command_line(target_command_->argv()); 298 CommandLine command_line(target_command_->argv());
339 command_line.AppendSwitchASCII(kDaemonPipeSwitchName, pipe_handle); 299 command_line.AppendSwitchASCII(kDaemonPipeSwitchName, pipe_handle);
340 300
341 // Create our own window station and desktop accessible by |logon_sid|. 301 // Create our own window station and desktop accessible by |logon_sid|.
342 WindowStationAndDesktop handles; 302 WindowStationAndDesktop handles;
343 if (!CreateWindowStationAndDesktop(logon_sid.Pass(), &handles)) { 303 if (!CreateWindowStationAndDesktop(logon_sid.Pass(), &handles)) {
344 LOG_GETLASTERROR(ERROR) 304 LOG_GETLASTERROR(ERROR)
345 << "Failed to create a window station and desktop"; 305 << "Failed to create a window station and desktop";
346 return false; 306 ReportFatalError();
307 return;
347 } 308 }
348 309
349 // Try to launch the worker process. The launched process inherits 310 // Try to launch the worker process. The launched process inherits
350 // the window station, desktop and pipe handles, created above. 311 // the window station, desktop and pipe handles, created above.
351 ScopedHandle worker_thread; 312 ScopedHandle worker_thread;
352 worker_process_.Close();
353 if (!LaunchProcessWithToken(command_line.GetProgram(), 313 if (!LaunchProcessWithToken(command_line.GetProgram(),
354 command_line.GetCommandLineString(), 314 command_line.GetCommandLineString(),
355 token, 315 token,
356 &process_attributes, 316 &process_attributes,
357 &thread_attributes, 317 &thread_attributes,
358 true, 318 true,
359 0, 319 0,
360 NULL, 320 NULL,
361 &worker_process_, 321 &worker_process,
362 &worker_thread)) { 322 &worker_thread)) {
363 return false; 323 ReportFatalError();
324 return;
364 } 325 }
365 } 326 }
366 327
367 // Return a handle that the caller can wait on to get notified when 328 channel_ = server.Pass();
368 // the process terminates. 329 ReportProcessLaunched(worker_process.Pass());
369 ScopedHandle process_exit_event; 330 }
331
332 void UnprivilegedProcessDelegate::Send(IPC::Message* message) {
333 DCHECK(CalledOnValidThread());
334
335 if (channel_) {
336 channel_->Send(message);
337 } else {
338 delete message;
339 }
340 }
341
342 void UnprivilegedProcessDelegate::CloseChannel() {
343 DCHECK(CalledOnValidThread());
344
345 channel_.reset();
346 }
347
348 void UnprivilegedProcessDelegate::KillProcess() {
349 DCHECK(CalledOnValidThread());
350
351 channel_.reset();
352
353 if (worker_process_.IsValid()) {
354 TerminateProcess(worker_process_, CONTROL_C_EXIT);
355 worker_process_.Close();
356 }
357 }
358
359 bool UnprivilegedProcessDelegate::OnMessageReceived(
360 const IPC::Message& message) {
361 DCHECK(CalledOnValidThread());
362
363 return event_handler_->OnMessageReceived(message);
364 }
365
366 void UnprivilegedProcessDelegate::OnChannelConnected(int32 peer_pid) {
367 DCHECK(CalledOnValidThread());
368
369 DWORD pid = GetProcessId(worker_process_);
370 if (pid != static_cast<DWORD>(peer_pid)) {
371 LOG(ERROR) << "The actual client PID " << pid
372 << " does not match the one reported by the client: "
373 << peer_pid;
374 ReportFatalError();
375 return;
376 }
377
378 event_handler_->OnChannelConnected(peer_pid);
379 }
380
381 void UnprivilegedProcessDelegate::OnChannelError() {
382 DCHECK(CalledOnValidThread());
383
384 event_handler_->OnChannelError();
385 }
386
387 void UnprivilegedProcessDelegate::ReportFatalError() {
388 DCHECK(CalledOnValidThread());
389
390 channel_.reset();
391
392 WorkerProcessLauncher* event_handler = event_handler_;
393 event_handler_ = NULL;
394 event_handler->OnFatalError();
395 }
396
397 void UnprivilegedProcessDelegate::ReportProcessLaunched(
398 base::win::ScopedHandle worker_process) {
399 DCHECK(CalledOnValidThread());
400 DCHECK(!worker_process_.IsValid());
401
402 worker_process_ = worker_process.Pass();
403
404 // Report a handle that can be used to wait for the worker process completion,
405 // query information about the process and duplicate handles.
406 DWORD desired_access =
407 SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION;
408 ScopedHandle limited_handle;
370 if (!DuplicateHandle(GetCurrentProcess(), 409 if (!DuplicateHandle(GetCurrentProcess(),
371 worker_process_, 410 worker_process_,
372 GetCurrentProcess(), 411 GetCurrentProcess(),
373 process_exit_event.Receive(), 412 limited_handle.Receive(),
374 SYNCHRONIZE, 413 desired_access,
375 FALSE, 414 FALSE,
376 0)) { 415 0)) {
377 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle"; 416 LOG_GETLASTERROR(ERROR) << "Failed to duplicate a handle";
378 KillProcess(CONTROL_C_EXIT); 417 ReportFatalError();
379 return false; 418 return;
380 } 419 }
381 420
382 channel_ = server.Pass(); 421 event_handler_->OnProcessLaunched(limited_handle.Pass());
383 *process_exit_event_out = process_exit_event.Pass();
384 return true;
385 } 422 }
386 423
387 } // namespace remoting 424 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/host/win/unprivileged_process_delegate.h ('k') | remoting/host/win/worker_process_launcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698