Home | History | Annotate | Download | only in shell
      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