1 // Copyright 2014 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 "mojo/shell/child_process_host.h" 6 7 #include "base/base_switches.h" 8 #include "base/bind.h" 9 #include "base/command_line.h" 10 #include "base/location.h" 11 #include "base/logging.h" 12 #include "base/macros.h" 13 #include "base/process/kill.h" 14 #include "base/process/launch.h" 15 #include "base/strings/string_number_conversions.h" 16 #include "base/task_runner.h" 17 #include "base/task_runner_util.h" 18 #include "mojo/shell/context.h" 19 #include "mojo/shell/switches.h" 20 21 namespace mojo { 22 namespace shell { 23 24 ChildProcessHost::ChildProcessHost(Context* context, 25 Delegate* delegate, 26 ChildProcess::Type type) 27 : context_(context), 28 delegate_(delegate), 29 type_(type), 30 child_process_handle_(base::kNullProcessHandle) { 31 DCHECK(delegate); 32 platform_channel_ = platform_channel_pair_.PassServerHandle(); 33 CHECK(platform_channel_.is_valid()); 34 } 35 36 ChildProcessHost::~ChildProcessHost() { 37 if (child_process_handle_ != base::kNullProcessHandle) { 38 LOG(WARNING) << "Destroying ChildProcessHost with unjoined child"; 39 base::CloseProcessHandle(child_process_handle_); 40 child_process_handle_ = base::kNullProcessHandle; 41 } 42 } 43 44 void ChildProcessHost::Start() { 45 DCHECK_EQ(child_process_handle_, base::kNullProcessHandle); 46 47 delegate_->WillStart(); 48 49 CHECK(base::PostTaskAndReplyWithResult( 50 context_->task_runners()->blocking_pool(), 51 FROM_HERE, 52 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), 53 base::Bind(&ChildProcessHost::DidLaunch, base::Unretained(this)))); 54 } 55 56 int ChildProcessHost::Join() { 57 DCHECK_NE(child_process_handle_, base::kNullProcessHandle); 58 int rv = -1; 59 // Note: |WaitForExitCode()| closes the process handle. 60 LOG_IF(ERROR, !base::WaitForExitCode(child_process_handle_, &rv)) 61 << "Failed to wait for child process"; 62 child_process_handle_ = base::kNullProcessHandle; 63 return rv; 64 } 65 66 bool ChildProcessHost::DoLaunch() { 67 static const char* kForwardSwitches[] = { 68 switches::kTraceToConsole, 69 switches::kV, 70 switches::kVModule, 71 }; 72 73 const base::CommandLine* parent_command_line = 74 base::CommandLine::ForCurrentProcess(); 75 base::CommandLine child_command_line(parent_command_line->GetProgram()); 76 child_command_line.CopySwitchesFrom(*parent_command_line, kForwardSwitches, 77 arraysize(kForwardSwitches)); 78 child_command_line.AppendSwitchASCII( 79 switches::kChildProcessType, base::IntToString(static_cast<int>(type_))); 80 81 embedder::HandlePassingInformation handle_passing_info; 82 platform_channel_pair_.PrepareToPassClientHandleToChildProcess( 83 &child_command_line, &handle_passing_info); 84 85 base::LaunchOptions options; 86 #if defined(OS_WIN) 87 options.start_hidden = true; 88 options.handles_to_inherit = &handle_passing_info; 89 #elif defined(OS_POSIX) 90 options.fds_to_remap = &handle_passing_info; 91 #endif 92 93 if (!base::LaunchProcess(child_command_line, options, &child_process_handle_)) 94 return false; 95 96 platform_channel_pair_.ChildProcessLaunched(); 97 return true; 98 } 99 100 void ChildProcessHost::DidLaunch(bool success) { 101 delegate_->DidStart(success); 102 } 103 104 } // namespace shell 105 } // namespace mojo 106