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 21namespace mojo { 22namespace shell { 23 24ChildProcessHost::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 36ChildProcessHost::~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 44void 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 56int 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 66bool 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 100void ChildProcessHost::DidLaunch(bool success) { 101 delegate_->DidStart(success); 102} 103 104} // namespace shell 105} // namespace mojo 106