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