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

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

Issue 1801963002: Change primordial pipes to ShellClient (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase onto catalog CL Created 4 years, 9 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_base.h" 5 #include "mojo/shell/runner/host/child_process_base.h"
6 6
7 #include <stdint.h>
8
9 #include <utility>
10
11 #include "base/base_switches.h"
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/command_line.h"
15 #include "base/debug/stack_trace.h"
16 #include "base/files/file_path.h"
17 #include "base/location.h"
18 #include "base/logging.h" 7 #include "base/logging.h"
19 #include "base/macros.h" 8 #include "base/macros.h"
20 #include "base/memory/ref_counted.h" 9 #include "base/memory/ref_counted.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
23 #include "base/single_thread_task_runner.h" 11 #include "base/single_thread_task_runner.h"
24 #include "base/synchronization/waitable_event.h" 12 #include "base/synchronization/waitable_event.h"
25 #include "base/thread_task_runner_handle.h"
26 #include "base/threading/thread.h" 13 #include "base/threading/thread.h"
27 #include "base/threading/thread_checker.h"
28 #include "mojo/edk/embedder/embedder.h" 14 #include "mojo/edk/embedder/embedder.h"
29 #include "mojo/edk/embedder/platform_channel_pair.h"
30 #include "mojo/edk/embedder/process_delegate.h" 15 #include "mojo/edk/embedder/process_delegate.h"
31 #include "mojo/edk/embedder/scoped_platform_handle.h" 16 #include "mojo/shell/runner/common/client_util.h"
32 #include "mojo/message_pump/message_pump_mojo.h"
33 #include "mojo/public/cpp/bindings/binding.h"
34 #include "mojo/public/cpp/system/core.h"
35 #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h"
36 #include "mojo/shell/runner/common/switches.h"
37 #include "mojo/shell/runner/init.h"
38 17
39 namespace mojo { 18 namespace mojo {
40 namespace shell { 19 namespace shell {
41 20
42 namespace { 21 namespace {
43 22
44 // Blocker --------------------------------------------------------------------- 23 // Should be created and initialized on the main thread and kept alive as long
45 24 // a Mojo application is running in the current process.
46 // Blocks a thread until another thread unblocks it, at which point it unblocks 25 class ScopedAppContext : public edk::ProcessDelegate {
47 // and runs a closure provided by that thread.
48 class Blocker {
49 public: 26 public:
50 class Unblocker { 27 ScopedAppContext()
51 public: 28 : io_thread_("io_thread"), wait_for_shutdown_event_(true, false) {
52 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {}
53 ~Unblocker() {}
54
55 void Unblock(base::Closure run_after) {
56 DCHECK(blocker_);
57 DCHECK(blocker_->run_after_.is_null());
58 blocker_->run_after_ = run_after;
59 blocker_->event_.Signal();
60 blocker_ = nullptr;
61 }
62
63 private:
64 Blocker* blocker_;
65
66 // Copy and assign allowed.
67 };
68
69 Blocker() : event_(true, false) {}
70 ~Blocker() {}
71
72 void Block() {
73 DCHECK(run_after_.is_null());
74 event_.Wait();
75 if (!run_after_.is_null())
76 run_after_.Run();
77 }
78
79 Unblocker GetUnblocker() { return Unblocker(this); }
80
81 private:
82 base::WaitableEvent event_;
83 base::Closure run_after_;
84
85 DISALLOW_COPY_AND_ASSIGN(Blocker);
86 };
87
88 // AppContext ------------------------------------------------------------------
89
90 class ChildControllerImpl;
91
92 // Should be created and initialized on the main thread.
93 class AppContext : public edk::ProcessDelegate {
94 public:
95 AppContext()
96 : io_thread_("io_thread"), controller_thread_("controller_thread") {}
97 ~AppContext() override {}
98
99 void Init() {
100 // Initialize Mojo before starting any threads. 29 // Initialize Mojo before starting any threads.
101 edk::Init(); 30 edk::Init();
102 31
103 // Create and start our I/O thread. 32 // Create and start our I/O thread.
104 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0); 33 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
105 CHECK(io_thread_.StartWithOptions(io_thread_options)); 34 CHECK(io_thread_.StartWithOptions(io_thread_options));
106 io_runner_ = io_thread_.task_runner().get(); 35 io_runner_ = io_thread_.task_runner().get();
107 CHECK(io_runner_.get()); 36 CHECK(io_runner_.get());
108 37
109 // This must be created before controller_thread_ since MessagePumpMojo will
110 // create a message pipe which requires this code to be run first.
111 edk::InitIPCSupport(this, io_runner_); 38 edk::InitIPCSupport(this, io_runner_);
39 edk::SetParentPipeHandleFromCommandLine();
112 } 40 }
113 41
114 void StartControllerThread() { 42 ~ScopedAppContext() override {
115 // Create and start our controller thread. 43 edk::ShutdownIPCSupport();
116 base::Thread::Options controller_thread_options; 44 wait_for_shutdown_event_.Wait();
117 controller_thread_options.message_loop_type =
118 base::MessageLoop::TYPE_CUSTOM;
119 controller_thread_options.message_pump_factory =
120 base::Bind(&common::MessagePumpMojo::Create);
121 CHECK(controller_thread_.StartWithOptions(controller_thread_options));
122 controller_runner_ = controller_thread_.task_runner().get();
123 CHECK(controller_runner_.get());
124 }
125
126 void Shutdown() {
127 Blocker blocker;
128 shutdown_unblocker_ = blocker.GetUnblocker();
129 controller_runner_->PostTask(
130 FROM_HERE, base::Bind(&AppContext::ShutdownOnControllerThread,
131 base::Unretained(this)));
132 blocker.Block();
133 }
134
135 base::SingleThreadTaskRunner* io_runner() const { return io_runner_.get(); }
136
137 base::SingleThreadTaskRunner* controller_runner() const {
138 return controller_runner_.get();
139 }
140
141 ChildControllerImpl* controller() const { return controller_.get(); }
142
143 void set_controller(scoped_ptr<ChildControllerImpl> controller) {
144 controller_ = std::move(controller);
145 } 45 }
146 46
147 private: 47 private:
148 void ShutdownOnControllerThread() {
149 // First, destroy the controller.
150 controller_.reset();
151
152 // Next shutdown IPC. We'll unblock the main thread in OnShutdownComplete().
153 edk::ShutdownIPCSupport();
154 }
155
156 // ProcessDelegate implementation. 48 // ProcessDelegate implementation.
157 void OnShutdownComplete() override { 49 void OnShutdownComplete() override {
158 shutdown_unblocker_.Unblock(base::Closure()); 50 wait_for_shutdown_event_.Signal();
159 } 51 }
160 52
161 base::Thread io_thread_; 53 base::Thread io_thread_;
162 scoped_refptr<base::SingleThreadTaskRunner> io_runner_; 54 scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
163 55
164 base::Thread controller_thread_; 56 // Used to unblock the main thread on shutdown.
165 scoped_refptr<base::SingleThreadTaskRunner> controller_runner_; 57 base::WaitableEvent wait_for_shutdown_event_;
166 58
167 // Accessed only on the controller thread. 59 DISALLOW_COPY_AND_ASSIGN(ScopedAppContext);
168 scoped_ptr<ChildControllerImpl> controller_;
169
170 // Used to unblock the main thread on shutdown.
171 Blocker::Unblocker shutdown_unblocker_;
172
173 DISALLOW_COPY_AND_ASSIGN(AppContext);
174 }; 60 };
175 61
176 // ChildControllerImpl ------------------------------------------------------
177
178 class ChildControllerImpl : public mojom::ShellClientFactory {
179 public:
180 ~ChildControllerImpl() override {
181 DCHECK(thread_checker_.CalledOnValidThread());
182 }
183
184 // To be executed on the controller thread. Creates the |ChildController|,
185 // etc.
186 static void Init(AppContext* app_context,
187 const RunCallback& run_callback,
188 ScopedMessagePipeHandle host_message_pipe,
189 const Blocker::Unblocker& unblocker) {
190 DCHECK(app_context);
191 DCHECK(host_message_pipe.is_valid());
192
193 DCHECK(!app_context->controller());
194
195 scoped_ptr<ChildControllerImpl> impl(
196 new ChildControllerImpl(app_context, run_callback, unblocker));
197
198 impl->Bind(std::move(host_message_pipe));
199
200 app_context->set_controller(std::move(impl));
201 }
202
203 void Bind(ScopedMessagePipeHandle handle) {
204 binding_.Bind(std::move(handle));
205 binding_.set_connection_error_handler([this]() { OnConnectionError(); });
206 }
207
208 void OnConnectionError() {
209 // A connection error means the connection to the shell is lost. This is not
210 // recoverable.
211 LOG(ERROR) << "Connection error to the shell.";
212 _exit(1);
213 }
214
215 // |mojom::ShellClientFactory| methods:
216 void CreateShellClient(mojom::ShellClientRequest request,
217 const String& name) override {
218 DCHECK(thread_checker_.CalledOnValidThread());
219 unblocker_.Unblock(base::Bind(run_callback_, base::Passed(&request)));
220 }
221
222 private:
223 ChildControllerImpl(AppContext* app_context,
224 const RunCallback& run_callback,
225 const Blocker::Unblocker& unblocker)
226 : run_callback_(run_callback), unblocker_(unblocker), binding_(this) {}
227
228 base::ThreadChecker thread_checker_;
229 RunCallback run_callback_;
230 Blocker::Unblocker unblocker_;
231
232 Binding<mojom::ShellClientFactory> binding_;
233
234 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl);
235 };
236
237 ScopedMessagePipeHandle InitializeHostMessagePipe(
238 edk::ScopedPlatformHandle platform_channel,
239 scoped_refptr<base::TaskRunner> io_task_runner) {
240 edk::SetParentPipeHandle(std::move(platform_channel));
241 std::string primordial_pipe_token =
242 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
243 switches::kPrimordialPipeToken);
244 return edk::CreateChildMessagePipe(primordial_pipe_token);
245 }
246
247 } // namespace 62 } // namespace
248 63
249 void ChildProcessMain(const RunCallback& callback) { 64 void ChildProcessMain(const RunCallback& callback) {
250 const base::CommandLine& command_line =
251 *base::CommandLine::ForCurrentProcess();
252 edk::ScopedPlatformHandle platform_channel =
253 edk::PlatformChannelPair::PassClientHandleFromParentProcess(command_line);
254 CHECK(platform_channel.is_valid());
255
256 DCHECK(!base::MessageLoop::current()); 65 DCHECK(!base::MessageLoop::current());
257 66
258 Blocker blocker; 67 ScopedAppContext app_context;
259 AppContext app_context; 68 callback.Run(GetShellClientRequestFromCommandLine());
260 app_context.Init();
261 app_context.StartControllerThread();
262
263 ScopedMessagePipeHandle host_pipe = InitializeHostMessagePipe(
264 std::move(platform_channel), app_context.io_runner());
265 app_context.controller_runner()->PostTask(
266 FROM_HERE, base::Bind(&ChildControllerImpl::Init, &app_context, callback,
267 base::Passed(&host_pipe), blocker.GetUnblocker()));
268
269 // This will block, then run whatever the controller wants.
270 blocker.Block();
271
272 app_context.Shutdown();
273 } 69 }
274 70
275 } // namespace shell 71 } // namespace shell
276 } // namespace mojo 72 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/shell/runner/host/child_process_base.h ('k') | mojo/shell/runner/host/child_process_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698