Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: mojo/shell/runner/host/child_process_host.cc

Issue 1585493002: [mojo] Ports EDK (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "mojo/shell/runner/host/child_process_host.h" 5 #include "mojo/shell/runner/host/child_process_host.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/process/kill.h" 17 #include "base/process/kill.h"
18 #include "base/process/launch.h" 18 #include "base/process/launch.h"
19 #include "base/task_runner.h" 19 #include "base/task_runner.h"
20 #include "base/thread_task_runner_handle.h" 20 #include "base/thread_task_runner_handle.h"
21 #include "mojo/edk/embedder/embedder.h"
21 #include "mojo/public/cpp/bindings/interface_ptr_info.h" 22 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
22 #include "mojo/public/cpp/system/core.h" 23 #include "mojo/public/cpp/system/core.h"
23 #include "mojo/shell/runner/host/switches.h" 24 #include "mojo/shell/runner/host/switches.h"
24 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" 25 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
25 26
26 #if defined(OS_LINUX) && !defined(OS_ANDROID) 27 #if defined(OS_LINUX) && !defined(OS_ANDROID)
27 #include "sandbox/linux/services/namespace_sandbox.h" 28 #include "sandbox/linux/services/namespace_sandbox.h"
28 #endif 29 #endif
29 30
30 #if defined(OS_WIN) 31 #if defined(OS_WIN)
31 #include "base/win/windows_version.h" 32 #include "base/win/windows_version.h"
32 #endif 33 #endif
33 34
34 namespace mojo { 35 namespace mojo {
35 namespace shell { 36 namespace shell {
36 37
38 ChildProcessHost::PipeHolder::PipeHolder() {}
39
40 void ChildProcessHost::PipeHolder::Reject() {
41 base::AutoLock lock(lock_);
42 reject_pipe_ = true;
43 pipe_.reset();
44 }
45
46 void ChildProcessHost::PipeHolder::SetPipe(ScopedMessagePipeHandle pipe) {
47 base::AutoLock lock(lock_);
48 DCHECK(!pipe_.is_valid());
49 if (!reject_pipe_)
50 pipe_ = std::move(pipe);
51 }
52
53 ScopedMessagePipeHandle ChildProcessHost::PipeHolder::PassPipe() {
54 base::AutoLock lock(lock_);
55 DCHECK(pipe_.is_valid());
56 return std::move(pipe_);
57 }
58
59 ChildProcessHost::PipeHolder::~PipeHolder() {}
60
37 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, 61 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner,
38 bool start_sandboxed, 62 bool start_sandboxed,
39 const base::FilePath& app_path) 63 const base::FilePath& app_path)
40 : launch_process_runner_(launch_process_runner), 64 : launch_process_runner_(launch_process_runner),
41 start_sandboxed_(start_sandboxed), 65 start_sandboxed_(start_sandboxed),
42 app_path_(app_path), 66 app_path_(app_path),
43 channel_info_(nullptr), 67 channel_info_(nullptr),
44 start_child_process_event_(false, false), 68 start_child_process_event_(false, false),
45 weak_factory_(this) { 69 weak_factory_(this) {
46 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) 70 pipe_holder_ = new PipeHolder();
47 serializer_platform_channel_pair_.reset(new edk::PlatformChannelPair(true)); 71 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
48 72 node_channel_.reset(new edk::PlatformChannelPair);
49 child_message_pipe_ = embedder::CreateChannel( 73 primordial_pipe_token_ = edk::GenerateRandomToken();
50 platform_channel_pair_.PassServerHandle(), 74 } else {
51 base::Bind(&ChildProcessHost::DidCreateChannel, base::Unretained(this)), 75 pipe_holder_->SetPipe(embedder::CreateChannel(
52 base::ThreadTaskRunnerHandle::Get()); 76 platform_channel_pair_.PassServerHandle(),
77 base::Bind(&ChildProcessHost::DidCreateChannel, base::Unretained(this)),
78 base::ThreadTaskRunnerHandle::Get()));
79 OnMessagePipeCreated();
80 }
53 } 81 }
54 82
55 ChildProcessHost::ChildProcessHost(ScopedHandle channel) 83 ChildProcessHost::ChildProcessHost(ScopedHandle channel)
56 : launch_process_runner_(nullptr), 84 : launch_process_runner_(nullptr),
57 start_sandboxed_(false), 85 start_sandboxed_(false),
58 channel_info_(nullptr), 86 channel_info_(nullptr),
59 start_child_process_event_(false, false), 87 start_child_process_event_(false, false),
60 weak_factory_(this) { 88 weak_factory_(this) {
61 CHECK(channel.is_valid()); 89 CHECK(channel.is_valid());
62 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); 90 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value()));
63 controller_.Bind(InterfacePtrInfo<ChildController>(std::move(handle), 0u)); 91 controller_.Bind(InterfacePtrInfo<ChildController>(std::move(handle), 0u));
64 } 92 }
65 93
66 ChildProcessHost::~ChildProcessHost() { 94 ChildProcessHost::~ChildProcessHost() {
67 if (!app_path_.empty()) 95 if (!app_path_.empty())
68 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; 96 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join";
69 } 97 }
70 98
71 void ChildProcessHost::Start( 99 void ChildProcessHost::Start(const ProcessReadyCallback& callback) {
72 const base::Callback<void(base::ProcessId)>& pid_available_callback) {
73 DCHECK(!child_process_.IsValid()); 100 DCHECK(!child_process_.IsValid());
74 DCHECK(child_message_pipe_.is_valid()); 101 DCHECK(process_ready_callback_.is_null());
75 102
103 process_ready_callback_ = callback;
76 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { 104 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
77 std::string client_handle_as_string = 105 // With the new EDK, bootstrap message pipes are created asynchronously.
78 serializer_platform_channel_pair_ 106 // We recieve the bound pipe (if successful) on an arbitrary thread,
79 ->PrepareToPassClientHandleToChildProcessAsString( 107 // stash it in the thread-safe |pipe_holder_|, and then try to call
80 &handle_passing_info_); 108 // OnMessagePipeCreated() on the host's main thread.
81 // We can't send the MP for the token serializer implementation as a 109 //
82 // platform handle, because that would require the other side to use the 110 // Because of the way the launcher process shuts down, it's possible for
83 // token initializer itself! So instead we send it as a string. 111 // the main thread's MessageLoop to stop running (but not yet be destroyed!)
84 MojoResult rv = MojoWriteMessage( 112 // while this boostrap is pending, resulting in OnMessagePipeCreated() never
85 child_message_pipe_.get().value(), client_handle_as_string.c_str(), 113 // being called.
86 static_cast<uint32_t>(client_handle_as_string.size()), nullptr, 0, 114 //
87 MOJO_WRITE_MESSAGE_FLAG_NONE); 115 // A typical child process (i.e. one using ApplicationImpl to bind the other
88 DCHECK_EQ(rv, MOJO_RESULT_OK); 116 // end of this pipe) may hang forever waiting for an Initialize() message
117 // unless the pipe is closed. This in turn means that Join() could hang
118 // waiting for the process to exit. Deadlock!
119 //
120 // |pipe_holder_| exists for this reason. If it's still holding onto the
121 // pipe when Join() is called, the pipe will be closed.
122 DCHECK(!primordial_pipe_token_.empty());
123 edk::CreateParentMessagePipe(
124 primordial_pipe_token_,
125 base::Bind(&OnParentMessagePipeCreated, pipe_holder_,
126 base::ThreadTaskRunnerHandle::Get(),
127 base::Bind(&ChildProcessHost::OnMessagePipeCreated,
128 weak_factory_.GetWeakPtr())));
89 } 129 }
90 130
91 controller_.Bind(
92 InterfacePtrInfo<ChildController>(std::move(child_message_pipe_), 0u));
93
94 launch_process_runner_->PostTaskAndReply( 131 launch_process_runner_->PostTaskAndReply(
95 FROM_HERE, 132 FROM_HERE,
96 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), 133 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)),
97 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr(), 134 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr()));
98 pid_available_callback));
99 } 135 }
100 136
101 int ChildProcessHost::Join() { 137 int ChildProcessHost::Join() {
102 if (controller_) // We use this as a signal that Start was called. 138 if (controller_) // We use this as a signal that Start was called.
103 start_child_process_event_.Wait(); 139 start_child_process_event_.Wait();
140
104 controller_ = ChildControllerPtr(); 141 controller_ = ChildControllerPtr();
105 DCHECK(child_process_.IsValid()); 142 DCHECK(child_process_.IsValid());
143
144 // Ensure the child pipe is closed even if it wasn't yet connected to the
145 // controller.
146 pipe_holder_->Reject();
147
106 int rv = -1; 148 int rv = -1;
107 LOG_IF(ERROR, !child_process_.WaitForExit(&rv)) 149 LOG_IF(ERROR, !child_process_.WaitForExit(&rv))
108 << "Failed to wait for child process"; 150 << "Failed to wait for child process";
151
109 child_process_.Close(); 152 child_process_.Close();
153
110 return rv; 154 return rv;
111 } 155 }
112 156
113 void ChildProcessHost::StartApp( 157 void ChildProcessHost::StartApp(
114 InterfaceRequest<Application> application_request, 158 InterfaceRequest<Application> application_request,
115 const ChildController::StartAppCallback& on_app_complete) { 159 const ChildController::StartAppCallback& on_app_complete) {
116 DCHECK(controller_); 160 DCHECK(controller_);
117 161
118 on_app_complete_ = on_app_complete; 162 on_app_complete_ = on_app_complete;
119 controller_->StartApp( 163 controller_->StartApp(
120 std::move(application_request), 164 std::move(application_request),
121 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr())); 165 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr()));
122 } 166 }
123 167
124 void ChildProcessHost::ExitNow(int32_t exit_code) { 168 void ChildProcessHost::ExitNow(int32_t exit_code) {
125 DCHECK(controller_); 169 DCHECK(controller_);
126 170
127 controller_->ExitNow(exit_code); 171 controller_->ExitNow(exit_code);
128 } 172 }
129 173
130 void ChildProcessHost::DidStart( 174 void ChildProcessHost::DidStart() {
131 const base::Callback<void(base::ProcessId)>& pid_available_callback) {
132 DVLOG(2) << "ChildProcessHost::DidStart()"; 175 DVLOG(2) << "ChildProcessHost::DidStart()";
133 176
134 if (child_process_.IsValid()) { 177 if (child_process_.IsValid()) {
135 pid_available_callback.Run(child_process_.Pid()); 178 MaybeNotifyProcessReady();
136 } else { 179 } else {
137 LOG(ERROR) << "Failed to start child process"; 180 LOG(ERROR) << "Failed to start child process";
138 AppCompleted(MOJO_RESULT_UNKNOWN); 181 AppCompleted(MOJO_RESULT_UNKNOWN);
139 } 182 }
140 } 183 }
141 184
142 void ChildProcessHost::DoLaunch() { 185 void ChildProcessHost::DoLaunch() {
143 const base::CommandLine* parent_command_line = 186 const base::CommandLine* parent_command_line =
144 base::CommandLine::ForCurrentProcess(); 187 base::CommandLine::ForCurrentProcess();
145 base::FilePath target_path = parent_command_line->GetProgram(); 188 base::FilePath target_path = parent_command_line->GetProgram();
146 // |app_path_| can be empty in tests. 189 // |app_path_| can be empty in tests.
147 if (!app_path_.MatchesExtension(FILE_PATH_LITERAL(".mojo")) && 190 if (!app_path_.MatchesExtension(FILE_PATH_LITERAL(".mojo")) &&
148 !app_path_.empty()) { 191 !app_path_.empty()) {
149 target_path = app_path_; 192 target_path = app_path_;
150 } 193 }
151 194
152 base::CommandLine child_command_line(target_path); 195 base::CommandLine child_command_line(target_path);
153 child_command_line.AppendArguments(*parent_command_line, false); 196 child_command_line.AppendArguments(*parent_command_line, false);
154 197
155 if (target_path != app_path_) 198 if (target_path != app_path_)
156 child_command_line.AppendSwitchPath(switches::kChildProcess, app_path_); 199 child_command_line.AppendSwitchPath(switches::kChildProcess, app_path_);
157 200
158 if (start_sandboxed_) 201 if (start_sandboxed_)
159 child_command_line.AppendSwitch(switches::kEnableSandbox); 202 child_command_line.AppendSwitch(switches::kEnableSandbox);
160 203
161 platform_channel_pair_.PrepareToPassClientHandleToChildProcess( 204 if (node_channel_.get()) {
162 &child_command_line, &handle_passing_info_); 205 node_channel_->PrepareToPassClientHandleToChildProcess(
206 &child_command_line, &handle_passing_info_);
207 }
208
209 child_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken,
210 primordial_pipe_token_);
163 211
164 base::LaunchOptions options; 212 base::LaunchOptions options;
165 #if defined(OS_WIN) 213 #if defined(OS_WIN)
166 if (base::win::GetVersion() >= base::win::VERSION_VISTA) { 214 if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
167 options.handles_to_inherit = &handle_passing_info_; 215 options.handles_to_inherit = &handle_passing_info_;
168 } else { 216 } else {
169 #if defined(OFFICIAL_BUILD) 217 #if defined(OFFICIAL_BUILD)
170 CHECK(false) << "Launching mojo process with inherit_handles is insecure!"; 218 CHECK(false) << "Launching mojo process with inherit_handles is insecure!";
171 #endif 219 #endif
172 options.inherit_handles = true; 220 options.inherit_handles = true;
(...skipping 30 matching lines...) Expand all
203 if (!child_process_.IsValid()) { 251 if (!child_process_.IsValid()) {
204 LOG(ERROR) << "Starting the process with a sandbox failed. Missing kernel" 252 LOG(ERROR) << "Starting the process with a sandbox failed. Missing kernel"
205 << " support."; 253 << " support.";
206 } 254 }
207 } else 255 } else
208 #endif 256 #endif
209 child_process_ = base::LaunchProcess(child_command_line, options); 257 child_process_ = base::LaunchProcess(child_command_line, options);
210 258
211 if (child_process_.IsValid()) { 259 if (child_process_.IsValid()) {
212 platform_channel_pair_.ChildProcessLaunched(); 260 platform_channel_pair_.ChildProcessLaunched();
213 if (serializer_platform_channel_pair_.get()) { 261 if (node_channel_.get()) {
214 serializer_platform_channel_pair_->ChildProcessLaunched(); 262 node_channel_->ChildProcessLaunched();
215 mojo::embedder::ChildProcessLaunched( 263 mojo::embedder::ChildProcessLaunched(
216 child_process_.Handle(), 264 child_process_.Handle(),
217 mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle( 265 mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle(
218 serializer_platform_channel_pair_->PassServerHandle().release(). 266 node_channel_->PassServerHandle().release().handle)));
219 handle)));
220 } 267 }
221 } 268 }
222 start_child_process_event_.Signal(); 269 start_child_process_event_.Signal();
223 } 270 }
224 271
225 void ChildProcessHost::AppCompleted(int32_t result) { 272 void ChildProcessHost::AppCompleted(int32_t result) {
226 if (!on_app_complete_.is_null()) { 273 if (!on_app_complete_.is_null()) {
227 auto on_app_complete = on_app_complete_; 274 auto on_app_complete = on_app_complete_;
228 on_app_complete_.reset(); 275 on_app_complete_.reset();
229 on_app_complete.Run(result); 276 on_app_complete.Run(result);
230 } 277 }
231 } 278 }
232 279
233 void ChildProcessHost::DidCreateChannel(embedder::ChannelInfo* channel_info) { 280 void ChildProcessHost::DidCreateChannel(embedder::ChannelInfo* channel_info) {
234 DVLOG(2) << "AppChildProcessHost::DidCreateChannel()"; 281 DVLOG(2) << "AppChildProcessHost::DidCreateChannel()";
235 282
236 DCHECK(channel_info || 283 DCHECK(channel_info ||
237 base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")); 284 base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk"));
238 channel_info_ = channel_info; 285 channel_info_ = channel_info;
239 } 286 }
240 287
288 void ChildProcessHost::OnMessagePipeCreated() {
289 controller_.Bind(
290 InterfacePtrInfo<ChildController>(pipe_holder_->PassPipe(), 0u));
291 MaybeNotifyProcessReady();
292 }
293
294 void ChildProcessHost::MaybeNotifyProcessReady() {
295 if (controller_.is_bound() && child_process_.IsValid())
296 process_ready_callback_.Run(child_process_.Pid());
297 }
298
299 // static
300 void ChildProcessHost::OnParentMessagePipeCreated(
301 scoped_refptr<PipeHolder> holder,
302 scoped_refptr<base::TaskRunner> callback_task_runner,
303 const base::Closure& callback,
304 ScopedMessagePipeHandle pipe) {
305 holder->SetPipe(std::move(pipe));
306 callback_task_runner->PostTask(FROM_HERE, callback);
307 }
308
241 } // namespace shell 309 } // namespace shell
242 } // namespace mojo 310 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698