OLD | NEW |
---|---|
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/edk/embedder/embedder.h" |
22 #include "mojo/public/cpp/bindings/interface_ptr_info.h" | 22 #include "mojo/public/cpp/bindings/interface_ptr_info.h" |
23 #include "mojo/public/cpp/system/core.h" | 23 #include "mojo/public/cpp/system/core.h" |
24 #include "mojo/shell/runner/common/switches.h" | 24 #include "mojo/shell/runner/common/switches.h" |
25 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" | |
26 | 25 |
27 #if defined(OS_LINUX) && !defined(OS_ANDROID) | 26 #if defined(OS_LINUX) && !defined(OS_ANDROID) |
28 #include "sandbox/linux/services/namespace_sandbox.h" | 27 #include "sandbox/linux/services/namespace_sandbox.h" |
29 #endif | 28 #endif |
30 | 29 |
31 #if defined(OS_WIN) | 30 #if defined(OS_WIN) |
32 #include "base/win/windows_version.h" | 31 #include "base/win/windows_version.h" |
33 #endif | 32 #endif |
34 | 33 |
35 namespace mojo { | 34 namespace mojo { |
(...skipping 21 matching lines...) Expand all Loading... | |
57 } | 56 } |
58 | 57 |
59 ChildProcessHost::PipeHolder::~PipeHolder() {} | 58 ChildProcessHost::PipeHolder::~PipeHolder() {} |
60 | 59 |
61 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, | 60 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, |
62 bool start_sandboxed, | 61 bool start_sandboxed, |
63 const base::FilePath& app_path) | 62 const base::FilePath& app_path) |
64 : launch_process_runner_(launch_process_runner), | 63 : launch_process_runner_(launch_process_runner), |
65 start_sandboxed_(start_sandboxed), | 64 start_sandboxed_(start_sandboxed), |
66 app_path_(app_path), | 65 app_path_(app_path), |
67 channel_info_(nullptr), | |
68 start_child_process_event_(false, false), | 66 start_child_process_event_(false, false), |
69 weak_factory_(this) { | 67 weak_factory_(this) { |
70 pipe_holder_ = new PipeHolder(); | 68 pipe_holder_ = new PipeHolder(); |
71 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { | 69 node_channel_.reset(new edk::PlatformChannelPair); |
72 node_channel_.reset(new edk::PlatformChannelPair); | 70 primordial_pipe_token_ = edk::GenerateRandomToken(); |
73 primordial_pipe_token_ = edk::GenerateRandomToken(); | |
74 } else { | |
75 pipe_holder_->SetPipe(embedder::CreateChannel( | |
76 platform_channel_pair_.PassServerHandle(), | |
77 base::Bind(&ChildProcessHost::DidCreateChannel, base::Unretained(this)), | |
78 base::ThreadTaskRunnerHandle::Get())); | |
79 OnMessagePipeCreated(); | |
80 } | |
81 } | 71 } |
82 | 72 |
83 ChildProcessHost::ChildProcessHost(ScopedHandle channel) | 73 ChildProcessHost::ChildProcessHost(ScopedHandle channel) |
84 : launch_process_runner_(nullptr), | 74 : launch_process_runner_(nullptr), |
85 start_sandboxed_(false), | 75 start_sandboxed_(false), |
86 channel_info_(nullptr), | |
87 start_child_process_event_(false, false), | 76 start_child_process_event_(false, false), |
88 weak_factory_(this) { | 77 weak_factory_(this) { |
89 CHECK(channel.is_valid()); | 78 CHECK(channel.is_valid()); |
90 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); | 79 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); |
91 controller_.Bind( | 80 controller_.Bind( |
92 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); | 81 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); |
93 } | 82 } |
94 | 83 |
95 ChildProcessHost::~ChildProcessHost() { | 84 ChildProcessHost::~ChildProcessHost() { |
96 if (!app_path_.empty()) | 85 if (!app_path_.empty()) |
97 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; | 86 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; |
98 } | 87 } |
99 | 88 |
100 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { | 89 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { |
101 DCHECK(!child_process_.IsValid()); | 90 DCHECK(!child_process_.IsValid()); |
102 DCHECK(process_ready_callback_.is_null()); | 91 DCHECK(process_ready_callback_.is_null()); |
103 | 92 |
104 process_ready_callback_ = callback; | 93 process_ready_callback_ = callback; |
105 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { | 94 // With the new EDK, bootstrap message pipes are created asynchronously. |
jam
2016/02/08 17:32:12
nit: remove new edk since there's only one now?
Ken Rockot(use gerrit already)
2016/02/08 17:51:18
Done
| |
106 // With the new EDK, bootstrap message pipes are created asynchronously. | 95 // We recieve the bound pipe (if successful) on an arbitrary thread, |
107 // We recieve the bound pipe (if successful) on an arbitrary thread, | 96 // stash it in the thread-safe |pipe_holder_|, and then try to call |
108 // stash it in the thread-safe |pipe_holder_|, and then try to call | 97 // OnMessagePipeCreated() on the host's main thread. |
109 // OnMessagePipeCreated() on the host's main thread. | 98 // |
110 // | 99 // Because of the way the launcher process shuts down, it's possible for |
111 // Because of the way the launcher process shuts down, it's possible for | 100 // the main thread's MessageLoop to stop running (but not yet be destroyed!) |
112 // the main thread's MessageLoop to stop running (but not yet be destroyed!) | 101 // while this boostrap is pending, resulting in OnMessagePipeCreated() never |
113 // while this boostrap is pending, resulting in OnMessagePipeCreated() never | 102 // being called. |
114 // being called. | 103 // |
115 // | 104 // A typical child process (i.e. one using ApplicationImpl to bind the other |
116 // A typical child process (i.e. one using ApplicationImpl to bind the other | 105 // end of this pipe) may hang forever waiting for an Initialize() message |
117 // end of this pipe) may hang forever waiting for an Initialize() message | 106 // unless the pipe is closed. This in turn means that Join() could hang |
118 // unless the pipe is closed. This in turn means that Join() could hang | 107 // waiting for the process to exit. Deadlock! |
119 // waiting for the process to exit. Deadlock! | 108 // |
120 // | 109 // |pipe_holder_| exists for this reason. If it's still holding onto the |
121 // |pipe_holder_| exists for this reason. If it's still holding onto the | 110 // pipe when Join() is called, the pipe will be closed. |
122 // pipe when Join() is called, the pipe will be closed. | 111 DCHECK(!primordial_pipe_token_.empty()); |
123 DCHECK(!primordial_pipe_token_.empty()); | 112 edk::CreateParentMessagePipe( |
124 edk::CreateParentMessagePipe( | 113 primordial_pipe_token_, |
125 primordial_pipe_token_, | 114 base::Bind(&OnParentMessagePipeCreated, pipe_holder_, |
126 base::Bind(&OnParentMessagePipeCreated, pipe_holder_, | 115 base::ThreadTaskRunnerHandle::Get(), |
127 base::ThreadTaskRunnerHandle::Get(), | 116 base::Bind(&ChildProcessHost::OnMessagePipeCreated, |
128 base::Bind(&ChildProcessHost::OnMessagePipeCreated, | 117 weak_factory_.GetWeakPtr()))); |
129 weak_factory_.GetWeakPtr()))); | |
130 } | |
131 | 118 |
132 launch_process_runner_->PostTaskAndReply( | 119 launch_process_runner_->PostTaskAndReply( |
133 FROM_HERE, | 120 FROM_HERE, |
134 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), | 121 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), |
135 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); | 122 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); |
136 } | 123 } |
137 | 124 |
138 int ChildProcessHost::Join() { | 125 int ChildProcessHost::Join() { |
139 if (controller_) // We use this as a signal that Start was called. | 126 if (controller_) // We use this as a signal that Start was called. |
140 start_child_process_event_.Wait(); | 127 start_child_process_event_.Wait(); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
254 << " support."; | 241 << " support."; |
255 } | 242 } |
256 } else | 243 } else |
257 #endif | 244 #endif |
258 child_process_ = base::LaunchProcess(child_command_line, options); | 245 child_process_ = base::LaunchProcess(child_command_line, options); |
259 | 246 |
260 if (child_process_.IsValid()) { | 247 if (child_process_.IsValid()) { |
261 platform_channel_pair_.ChildProcessLaunched(); | 248 platform_channel_pair_.ChildProcessLaunched(); |
262 if (node_channel_.get()) { | 249 if (node_channel_.get()) { |
263 node_channel_->ChildProcessLaunched(); | 250 node_channel_->ChildProcessLaunched(); |
264 mojo::embedder::ChildProcessLaunched( | 251 mojo::edk::ChildProcessLaunched( |
265 child_process_.Handle(), | 252 child_process_.Handle(), |
266 mojo::embedder::ScopedPlatformHandle(mojo::embedder::PlatformHandle( | 253 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle( |
267 node_channel_->PassServerHandle().release().handle))); | 254 node_channel_->PassServerHandle().release().handle))); |
268 } | 255 } |
269 } | 256 } |
270 start_child_process_event_.Signal(); | 257 start_child_process_event_.Signal(); |
271 } | 258 } |
272 | 259 |
273 void ChildProcessHost::AppCompleted(int32_t result) { | 260 void ChildProcessHost::AppCompleted(int32_t result) { |
274 if (!on_app_complete_.is_null()) { | 261 if (!on_app_complete_.is_null()) { |
275 auto on_app_complete = on_app_complete_; | 262 auto on_app_complete = on_app_complete_; |
276 on_app_complete_.reset(); | 263 on_app_complete_.reset(); |
277 on_app_complete.Run(result); | 264 on_app_complete.Run(result); |
278 } | 265 } |
279 } | 266 } |
280 | 267 |
281 void ChildProcessHost::DidCreateChannel(embedder::ChannelInfo* channel_info) { | |
282 DVLOG(2) << "AppChildProcessHost::DidCreateChannel()"; | |
283 | |
284 DCHECK(channel_info || | |
285 base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")); | |
286 channel_info_ = channel_info; | |
287 } | |
288 | |
289 void ChildProcessHost::OnMessagePipeCreated() { | 268 void ChildProcessHost::OnMessagePipeCreated() { |
290 controller_.Bind( | 269 controller_.Bind( |
291 InterfacePtrInfo<mojom::ChildController>(pipe_holder_->PassPipe(), 0u)); | 270 InterfacePtrInfo<mojom::ChildController>(pipe_holder_->PassPipe(), 0u)); |
292 MaybeNotifyProcessReady(); | 271 MaybeNotifyProcessReady(); |
293 } | 272 } |
294 | 273 |
295 void ChildProcessHost::MaybeNotifyProcessReady() { | 274 void ChildProcessHost::MaybeNotifyProcessReady() { |
296 if (controller_.is_bound() && child_process_.IsValid()) | 275 if (controller_.is_bound() && child_process_.IsValid()) |
297 process_ready_callback_.Run(child_process_.Pid()); | 276 process_ready_callback_.Run(child_process_.Pid()); |
298 } | 277 } |
299 | 278 |
300 // static | 279 // static |
301 void ChildProcessHost::OnParentMessagePipeCreated( | 280 void ChildProcessHost::OnParentMessagePipeCreated( |
302 scoped_refptr<PipeHolder> holder, | 281 scoped_refptr<PipeHolder> holder, |
303 scoped_refptr<base::TaskRunner> callback_task_runner, | 282 scoped_refptr<base::TaskRunner> callback_task_runner, |
304 const base::Closure& callback, | 283 const base::Closure& callback, |
305 ScopedMessagePipeHandle pipe) { | 284 ScopedMessagePipeHandle pipe) { |
306 holder->SetPipe(std::move(pipe)); | 285 holder->SetPipe(std::move(pipe)); |
307 callback_task_runner->PostTask(FROM_HERE, callback); | 286 callback_task_runner->PostTask(FROM_HERE, callback); |
308 } | 287 } |
309 | 288 |
310 } // namespace shell | 289 } // namespace shell |
311 } // namespace mojo | 290 } // namespace mojo |
OLD | NEW |