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

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

Issue 1675603002: [mojo-edk] Simplify multiprocess pipe bootstrap (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix some callers to work with sync APIs Created 4 years, 10 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
« no previous file with comments | « mojo/shell/runner/host/child_process_host.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
(...skipping 17 matching lines...) Expand all
28 #include "sandbox/linux/services/namespace_sandbox.h" 28 #include "sandbox/linux/services/namespace_sandbox.h"
29 #endif 29 #endif
30 30
31 #if defined(OS_WIN) 31 #if defined(OS_WIN)
32 #include "base/win/windows_version.h" 32 #include "base/win/windows_version.h"
33 #endif 33 #endif
34 34
35 namespace mojo { 35 namespace mojo {
36 namespace shell { 36 namespace shell {
37 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
61 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, 38 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner,
62 bool start_sandboxed, 39 bool start_sandboxed,
63 const base::FilePath& app_path) 40 const base::FilePath& app_path)
64 : launch_process_runner_(launch_process_runner), 41 : launch_process_runner_(launch_process_runner),
65 start_sandboxed_(start_sandboxed), 42 start_sandboxed_(start_sandboxed),
66 app_path_(app_path), 43 app_path_(app_path),
67 channel_info_(nullptr),
68 start_child_process_event_(false, false), 44 start_child_process_event_(false, false),
69 weak_factory_(this) { 45 weak_factory_(this) {
70 pipe_holder_ = new PipeHolder(); 46 node_channel_.reset(new edk::PlatformChannelPair);
71 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) { 47 primordial_pipe_token_ = edk::GenerateRandomToken();
72 node_channel_.reset(new edk::PlatformChannelPair); 48 controller_.Bind(
73 primordial_pipe_token_ = edk::GenerateRandomToken(); 49 InterfacePtrInfo<mojom::ChildController>(
74 } else { 50 edk::CreateParentMessagePipe(primordial_pipe_token_), 0u));
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 } 51 }
82 52
83 ChildProcessHost::ChildProcessHost(ScopedHandle channel) 53 ChildProcessHost::ChildProcessHost(ScopedHandle channel)
84 : launch_process_runner_(nullptr), 54 : launch_process_runner_(nullptr),
85 start_sandboxed_(false), 55 start_sandboxed_(false),
86 channel_info_(nullptr),
87 start_child_process_event_(false, false), 56 start_child_process_event_(false, false),
88 weak_factory_(this) { 57 weak_factory_(this) {
89 CHECK(channel.is_valid()); 58 CHECK(channel.is_valid());
90 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); 59 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value()));
91 controller_.Bind( 60 controller_.Bind(
92 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); 61 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u));
93 } 62 }
94 63
95 ChildProcessHost::~ChildProcessHost() { 64 ChildProcessHost::~ChildProcessHost() {
96 if (!app_path_.empty()) 65 if (!app_path_.empty())
97 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; 66 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join";
98 } 67 }
99 68
100 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { 69 void ChildProcessHost::Start(const ProcessReadyCallback& callback) {
101 DCHECK(!child_process_.IsValid()); 70 DCHECK(!child_process_.IsValid());
102 DCHECK(process_ready_callback_.is_null());
103
104 process_ready_callback_ = callback;
105 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
106 // With the new EDK, bootstrap message pipes are created asynchronously.
107 // We recieve the bound pipe (if successful) on an arbitrary thread,
108 // stash it in the thread-safe |pipe_holder_|, and then try to call
109 // OnMessagePipeCreated() on the host's main thread.
110 //
111 // Because of the way the launcher process shuts down, it's possible for
112 // the main thread's MessageLoop to stop running (but not yet be destroyed!)
113 // while this boostrap is pending, resulting in OnMessagePipeCreated() never
114 // being called.
115 //
116 // A typical child process (i.e. one using ShellConnection to bind the other
117 // end of this pipe) may hang forever waiting for an Initialize() message
118 // unless the pipe is closed. This in turn means that Join() could hang
119 // waiting for the process to exit. Deadlock!
120 //
121 // |pipe_holder_| exists for this reason. If it's still holding onto the
122 // pipe when Join() is called, the pipe will be closed.
123 DCHECK(!primordial_pipe_token_.empty());
124 edk::CreateParentMessagePipe(
125 primordial_pipe_token_,
126 base::Bind(&OnParentMessagePipeCreated, pipe_holder_,
127 base::ThreadTaskRunnerHandle::Get(),
128 base::Bind(&ChildProcessHost::OnMessagePipeCreated,
129 weak_factory_.GetWeakPtr())));
130 }
131
132 launch_process_runner_->PostTaskAndReply( 71 launch_process_runner_->PostTaskAndReply(
133 FROM_HERE, 72 FROM_HERE,
134 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), 73 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)),
135 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr())); 74 base::Bind(&ChildProcessHost::DidStart,
75 weak_factory_.GetWeakPtr(), callback));
136 } 76 }
137 77
138 int ChildProcessHost::Join() { 78 int ChildProcessHost::Join() {
139 if (controller_) // We use this as a signal that Start was called. 79 if (controller_) // We use this as a signal that Start was called.
140 start_child_process_event_.Wait(); 80 start_child_process_event_.Wait();
141 81
142 controller_ = mojom::ChildControllerPtr(); 82 controller_ = mojom::ChildControllerPtr();
143 DCHECK(child_process_.IsValid()); 83 DCHECK(child_process_.IsValid());
144 84
145 // Ensure the child pipe is closed even if it wasn't yet connected to the
146 // controller.
147 pipe_holder_->Reject();
148
149 int rv = -1; 85 int rv = -1;
150 LOG_IF(ERROR, !child_process_.WaitForExit(&rv)) 86 LOG_IF(ERROR, !child_process_.WaitForExit(&rv))
151 << "Failed to wait for child process"; 87 << "Failed to wait for child process";
152 88
153 child_process_.Close(); 89 child_process_.Close();
154 90
155 return rv; 91 return rv;
156 } 92 }
157 93
158 void ChildProcessHost::StartApp( 94 void ChildProcessHost::StartApp(
159 InterfaceRequest<mojom::ShellClient> request, 95 InterfaceRequest<mojom::ShellClient> request,
160 const mojom::ChildController::StartAppCallback& on_app_complete) { 96 const mojom::ChildController::StartAppCallback& on_app_complete) {
161 DCHECK(controller_); 97 DCHECK(controller_);
162 98
163 on_app_complete_ = on_app_complete; 99 on_app_complete_ = on_app_complete;
164 controller_->StartApp( 100 controller_->StartApp(
165 std::move(request), 101 std::move(request),
166 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr())); 102 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr()));
167 } 103 }
168 104
169 void ChildProcessHost::ExitNow(int32_t exit_code) { 105 void ChildProcessHost::ExitNow(int32_t exit_code) {
170 DCHECK(controller_); 106 DCHECK(controller_);
171 107
172 controller_->ExitNow(exit_code); 108 controller_->ExitNow(exit_code);
173 } 109 }
174 110
175 void ChildProcessHost::DidStart() { 111 void ChildProcessHost::DidStart(const ProcessReadyCallback& callback) {
176 DVLOG(2) << "ChildProcessHost::DidStart()"; 112 DVLOG(2) << "ChildProcessHost::DidStart()";
177 113
178 if (child_process_.IsValid()) { 114 if (child_process_.IsValid()) {
179 MaybeNotifyProcessReady(); 115 callback.Run(child_process_.Pid());
180 } else { 116 } else {
181 LOG(ERROR) << "Failed to start child process"; 117 LOG(ERROR) << "Failed to start child process";
182 AppCompleted(MOJO_RESULT_UNKNOWN); 118 AppCompleted(MOJO_RESULT_UNKNOWN);
183 } 119 }
184 } 120 }
185 121
186 void ChildProcessHost::DoLaunch() { 122 void ChildProcessHost::DoLaunch() {
187 const base::CommandLine* parent_command_line = 123 const base::CommandLine* parent_command_line =
188 base::CommandLine::ForCurrentProcess(); 124 base::CommandLine::ForCurrentProcess();
189 base::FilePath target_path = parent_command_line->GetProgram(); 125 base::FilePath target_path = parent_command_line->GetProgram();
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 } 207 }
272 208
273 void ChildProcessHost::AppCompleted(int32_t result) { 209 void ChildProcessHost::AppCompleted(int32_t result) {
274 if (!on_app_complete_.is_null()) { 210 if (!on_app_complete_.is_null()) {
275 auto on_app_complete = on_app_complete_; 211 auto on_app_complete = on_app_complete_;
276 on_app_complete_.reset(); 212 on_app_complete_.reset();
277 on_app_complete.Run(result); 213 on_app_complete.Run(result);
278 } 214 }
279 } 215 }
280 216
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() {
290 controller_.Bind(
291 InterfacePtrInfo<mojom::ChildController>(pipe_holder_->PassPipe(), 0u));
292 MaybeNotifyProcessReady();
293 }
294
295 void ChildProcessHost::MaybeNotifyProcessReady() {
296 if (controller_.is_bound() && child_process_.IsValid())
297 process_ready_callback_.Run(child_process_.Pid());
298 }
299
300 // static
301 void ChildProcessHost::OnParentMessagePipeCreated(
302 scoped_refptr<PipeHolder> holder,
303 scoped_refptr<base::TaskRunner> callback_task_runner,
304 const base::Closure& callback,
305 ScopedMessagePipeHandle pipe) {
306 holder->SetPipe(std::move(pipe));
307 callback_task_runner->PostTask(FROM_HERE, callback);
308 }
309
310 } // namespace shell 217 } // namespace shell
311 } // namespace mojo 218 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/runner/host/child_process_host.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698