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

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

Issue 1678333003: Revert of [mojo-edk] Simplify multiprocess pipe bootstrap (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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
38 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner, 61 ChildProcessHost::ChildProcessHost(base::TaskRunner* launch_process_runner,
39 bool start_sandboxed, 62 bool start_sandboxed,
40 const base::FilePath& app_path) 63 const base::FilePath& app_path)
41 : launch_process_runner_(launch_process_runner), 64 : launch_process_runner_(launch_process_runner),
42 start_sandboxed_(start_sandboxed), 65 start_sandboxed_(start_sandboxed),
43 app_path_(app_path), 66 app_path_(app_path),
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 node_channel_.reset(new edk::PlatformChannelPair); 70 pipe_holder_ = new PipeHolder();
47 primordial_pipe_token_ = edk::GenerateRandomToken(); 71 if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk")) {
48 controller_.Bind( 72 node_channel_.reset(new edk::PlatformChannelPair);
49 InterfacePtrInfo<mojom::ChildController>( 73 primordial_pipe_token_ = edk::GenerateRandomToken();
50 edk::CreateParentMessagePipe(primordial_pipe_token_), 0u)); 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 }
51 } 81 }
52 82
53 ChildProcessHost::ChildProcessHost(ScopedHandle channel) 83 ChildProcessHost::ChildProcessHost(ScopedHandle channel)
54 : launch_process_runner_(nullptr), 84 : launch_process_runner_(nullptr),
55 start_sandboxed_(false), 85 start_sandboxed_(false),
86 channel_info_(nullptr),
56 start_child_process_event_(false, false), 87 start_child_process_event_(false, false),
57 weak_factory_(this) { 88 weak_factory_(this) {
58 CHECK(channel.is_valid()); 89 CHECK(channel.is_valid());
59 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value())); 90 ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value()));
60 controller_.Bind( 91 controller_.Bind(
61 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u)); 92 InterfacePtrInfo<mojom::ChildController>(std::move(handle), 0u));
62 } 93 }
63 94
64 ChildProcessHost::~ChildProcessHost() { 95 ChildProcessHost::~ChildProcessHost() {
65 if (!app_path_.empty()) 96 if (!app_path_.empty())
66 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join"; 97 CHECK(!controller_) << "Destroying ChildProcessHost before calling Join";
67 } 98 }
68 99
69 void ChildProcessHost::Start(const ProcessReadyCallback& callback) { 100 void ChildProcessHost::Start(const ProcessReadyCallback& callback) {
70 DCHECK(!child_process_.IsValid()); 101 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
71 launch_process_runner_->PostTaskAndReply( 132 launch_process_runner_->PostTaskAndReply(
72 FROM_HERE, 133 FROM_HERE,
73 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)), 134 base::Bind(&ChildProcessHost::DoLaunch, base::Unretained(this)),
74 base::Bind(&ChildProcessHost::DidStart, 135 base::Bind(&ChildProcessHost::DidStart, weak_factory_.GetWeakPtr()));
75 weak_factory_.GetWeakPtr(), callback));
76 } 136 }
77 137
78 int ChildProcessHost::Join() { 138 int ChildProcessHost::Join() {
79 if (controller_) // We use this as a signal that Start was called. 139 if (controller_) // We use this as a signal that Start was called.
80 start_child_process_event_.Wait(); 140 start_child_process_event_.Wait();
81 141
82 controller_ = mojom::ChildControllerPtr(); 142 controller_ = mojom::ChildControllerPtr();
83 DCHECK(child_process_.IsValid()); 143 DCHECK(child_process_.IsValid());
84 144
145 // Ensure the child pipe is closed even if it wasn't yet connected to the
146 // controller.
147 pipe_holder_->Reject();
148
85 int rv = -1; 149 int rv = -1;
86 LOG_IF(ERROR, !child_process_.WaitForExit(&rv)) 150 LOG_IF(ERROR, !child_process_.WaitForExit(&rv))
87 << "Failed to wait for child process"; 151 << "Failed to wait for child process";
88 152
89 child_process_.Close(); 153 child_process_.Close();
90 154
91 return rv; 155 return rv;
92 } 156 }
93 157
94 void ChildProcessHost::StartApp( 158 void ChildProcessHost::StartApp(
95 InterfaceRequest<mojom::ShellClient> request, 159 InterfaceRequest<mojom::ShellClient> request,
96 const mojom::ChildController::StartAppCallback& on_app_complete) { 160 const mojom::ChildController::StartAppCallback& on_app_complete) {
97 DCHECK(controller_); 161 DCHECK(controller_);
98 162
99 on_app_complete_ = on_app_complete; 163 on_app_complete_ = on_app_complete;
100 controller_->StartApp( 164 controller_->StartApp(
101 std::move(request), 165 std::move(request),
102 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr())); 166 base::Bind(&ChildProcessHost::AppCompleted, weak_factory_.GetWeakPtr()));
103 } 167 }
104 168
105 void ChildProcessHost::ExitNow(int32_t exit_code) { 169 void ChildProcessHost::ExitNow(int32_t exit_code) {
106 DCHECK(controller_); 170 DCHECK(controller_);
107 171
108 controller_->ExitNow(exit_code); 172 controller_->ExitNow(exit_code);
109 } 173 }
110 174
111 void ChildProcessHost::DidStart(const ProcessReadyCallback& callback) { 175 void ChildProcessHost::DidStart() {
112 DVLOG(2) << "ChildProcessHost::DidStart()"; 176 DVLOG(2) << "ChildProcessHost::DidStart()";
113 177
114 if (child_process_.IsValid()) { 178 if (child_process_.IsValid()) {
115 callback.Run(child_process_.Pid()); 179 MaybeNotifyProcessReady();
116 } else { 180 } else {
117 LOG(ERROR) << "Failed to start child process"; 181 LOG(ERROR) << "Failed to start child process";
118 AppCompleted(MOJO_RESULT_UNKNOWN); 182 AppCompleted(MOJO_RESULT_UNKNOWN);
119 } 183 }
120 } 184 }
121 185
122 void ChildProcessHost::DoLaunch() { 186 void ChildProcessHost::DoLaunch() {
123 const base::CommandLine* parent_command_line = 187 const base::CommandLine* parent_command_line =
124 base::CommandLine::ForCurrentProcess(); 188 base::CommandLine::ForCurrentProcess();
125 base::FilePath target_path = parent_command_line->GetProgram(); 189 base::FilePath target_path = parent_command_line->GetProgram();
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 } 271 }
208 272
209 void ChildProcessHost::AppCompleted(int32_t result) { 273 void ChildProcessHost::AppCompleted(int32_t result) {
210 if (!on_app_complete_.is_null()) { 274 if (!on_app_complete_.is_null()) {
211 auto on_app_complete = on_app_complete_; 275 auto on_app_complete = on_app_complete_;
212 on_app_complete_.reset(); 276 on_app_complete_.reset();
213 on_app_complete.Run(result); 277 on_app_complete.Run(result);
214 } 278 }
215 } 279 }
216 280
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
217 } // namespace shell 310 } // namespace shell
218 } // namespace mojo 311 } // 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