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.
5 #include "mojo/runner/child_process_host.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/process/kill.h"
14 #include "base/process/launch.h"
15 #include "base/task_runner.h"
16 #include "base/task_runner_util.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "mojo/edk/embedder/embedder.h"
19 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
20 #include "mojo/public/cpp/system/core.h"
21 #include "mojo/runner/context.h"
22 #include "mojo/runner/switches.h"
23 #include "mojo/runner/task_runners.h"
25 #if defined(OS_LINUX) && !defined(OS_ANDROID)
26 #include "sandbox/linux/services/namespace_sandbox.h"
32 ChildProcessHost::ChildProcessHost(Context
* context
,
34 const base::FilePath
& app_path
,
37 start_sandboxed_(start_sandboxed
),
39 clean_app_path_(clean_app_path
),
40 channel_info_(nullptr) {
41 platform_channel_
= platform_channel_pair_
.PassServerHandle();
42 CHECK(platform_channel_
.is_valid());
45 ChildProcessHost::~ChildProcessHost() {
46 if (child_process_
.IsValid()) {
47 LOG(WARNING
) << "Destroying ChildProcessHost with unjoined child";
48 child_process_
.Close();
52 void ChildProcessHost::Start() {
53 DCHECK(!child_process_
.IsValid());
54 DCHECK(platform_channel_
.is_valid());
56 ScopedMessagePipeHandle
handle(embedder::CreateChannel(
57 platform_channel_
.Pass(),
58 base::Bind(&ChildProcessHost::DidCreateChannel
, base::Unretained(this)),
59 base::ThreadTaskRunnerHandle::Get()));
61 controller_
.Bind(InterfacePtrInfo
<ChildController
>(handle
.Pass(), 0u));
63 CHECK(base::PostTaskAndReplyWithResult(
64 context_
->task_runners()->blocking_pool(), FROM_HERE
,
65 base::Bind(&ChildProcessHost::DoLaunch
, base::Unretained(this)),
66 base::Bind(&ChildProcessHost::DidStart
, base::Unretained(this))));
69 int ChildProcessHost::Join() {
70 DCHECK(child_process_
.IsValid());
72 LOG_IF(ERROR
, !child_process_
.WaitForExit(&rv
))
73 << "Failed to wait for child process";
74 child_process_
.Close();
78 void ChildProcessHost::StartApp(
79 InterfaceRequest
<Application
> application_request
,
80 const ChildController::StartAppCallback
& on_app_complete
) {
83 on_app_complete_
= on_app_complete
;
84 controller_
->StartApp(
85 application_request
.Pass(),
86 base::Bind(&ChildProcessHost::AppCompleted
, base::Unretained(this)));
89 void ChildProcessHost::ExitNow(int32_t exit_code
) {
92 controller_
->ExitNow(exit_code
);
95 void ChildProcessHost::DidStart(bool success
) {
96 DVLOG(2) << "ChildProcessHost::DidStart()";
99 LOG(ERROR
) << "Failed to start child process";
100 AppCompleted(MOJO_RESULT_UNKNOWN
);
105 bool ChildProcessHost::DoLaunch() {
106 const base::CommandLine
* parent_command_line
=
107 base::CommandLine::ForCurrentProcess();
108 base::CommandLine
child_command_line(parent_command_line
->GetProgram());
109 child_command_line
.AppendArguments(*parent_command_line
, false);
110 child_command_line
.AppendSwitchPath(switches::kChildProcess
, app_path_
);
113 child_command_line
.AppendSwitch(switches::kDeleteAfterLoad
);
115 if (start_sandboxed_
)
116 child_command_line
.AppendSwitch(switches::kEnableSandbox
);
118 embedder::HandlePassingInformation handle_passing_info
;
119 platform_channel_pair_
.PrepareToPassClientHandleToChildProcess(
120 &child_command_line
, &handle_passing_info
);
122 base::LaunchOptions options
;
124 options
.handles_to_inherit
= &handle_passing_info
;
125 #elif defined(OS_POSIX)
126 handle_passing_info
.push_back(std::make_pair(STDIN_FILENO
, STDIN_FILENO
));
127 handle_passing_info
.push_back(std::make_pair(STDOUT_FILENO
, STDOUT_FILENO
));
128 handle_passing_info
.push_back(std::make_pair(STDERR_FILENO
, STDERR_FILENO
));
129 options
.fds_to_remap
= &handle_passing_info
;
131 DVLOG(2) << "Launching child with command line: "
132 << child_command_line
.GetCommandLineString();
133 #if defined(OS_LINUX) && !defined(OS_ANDROID)
134 if (start_sandboxed_
) {
136 sandbox::NamespaceSandbox::LaunchProcess(child_command_line
, options
);
137 if (!child_process_
.IsValid()) {
138 LOG(ERROR
) << "Starting the process with a sandbox failed. Missing kernel"
144 child_process_
= base::LaunchProcess(child_command_line
, options
);
146 if (!child_process_
.IsValid())
149 platform_channel_pair_
.ChildProcessLaunched();
153 void ChildProcessHost::AppCompleted(int32_t result
) {
154 if (!on_app_complete_
.is_null()) {
155 auto on_app_complete
= on_app_complete_
;
156 on_app_complete_
.reset();
157 on_app_complete
.Run(result
);
161 void ChildProcessHost::DidCreateChannel(embedder::ChannelInfo
* channel_info
) {
162 DVLOG(2) << "AppChildProcessHost::DidCreateChannel()";
165 channel_info_
= channel_info
;
168 } // namespace runner