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

Side by Side Diff: shell/app_child_process.cc

Issue 1055463004: Replace ChildProcess/AppChildProcess with a simple ChildMain(). (Closed) Base URL: https://github.com/domokit/mojo.git@simplify_child_6-x-simplify_child_5
Patch Set: rebased Created 5 years, 8 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 | « shell/app_child_process.h ('k') | shell/child_main.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "shell/app_child_process.h"
6
7 #include <unistd.h>
8
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/files/file_path.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/single_thread_task_runner.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/threading/thread.h"
21 #include "base/threading/thread_checker.h"
22 #include "mojo/common/message_pump_mojo.h"
23 #include "mojo/edk/embedder/embedder.h"
24 #include "mojo/edk/embedder/process_delegate.h"
25 #include "mojo/edk/embedder/simple_platform_support.h"
26 #include "mojo/public/cpp/system/core.h"
27 #include "shell/child_controller.mojom.h"
28 #include "shell/native_application_support.h"
29
30 namespace mojo {
31 namespace shell {
32
33 namespace {
34
35 // Blocker ---------------------------------------------------------------------
36
37 // Blocks a thread until another thread unblocks it, at which point it unblocks
38 // and runs a closure provided by that thread.
39 class Blocker {
40 public:
41 class Unblocker {
42 public:
43 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {}
44 ~Unblocker() {}
45
46 void Unblock(base::Closure run_after) {
47 DCHECK(blocker_);
48 DCHECK(blocker_->run_after_.is_null());
49 blocker_->run_after_ = run_after;
50 blocker_->event_.Signal();
51 blocker_ = nullptr;
52 }
53
54 private:
55 Blocker* blocker_;
56
57 // Copy and assign allowed.
58 };
59
60 Blocker() : event_(true, false) {}
61 ~Blocker() {}
62
63 void Block() {
64 DCHECK(run_after_.is_null());
65 event_.Wait();
66 run_after_.Run();
67 }
68
69 Unblocker GetUnblocker() { return Unblocker(this); }
70
71 private:
72 base::WaitableEvent event_;
73 base::Closure run_after_;
74
75 DISALLOW_COPY_AND_ASSIGN(Blocker);
76 };
77
78 // AppContext ------------------------------------------------------------------
79
80 class ChildControllerImpl;
81
82 // Should be created and initialized on the main thread.
83 class AppContext : public embedder::ProcessDelegate {
84 public:
85 AppContext()
86 : io_thread_("io_thread"), controller_thread_("controller_thread") {}
87 ~AppContext() override {}
88
89 void Init() {
90 // Initialize Mojo before starting any threads.
91 embedder::Init(make_scoped_ptr(new embedder::SimplePlatformSupport()));
92
93 // Create and start our I/O thread.
94 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
95 CHECK(io_thread_.StartWithOptions(io_thread_options));
96 io_runner_ = io_thread_.message_loop_proxy().get();
97 CHECK(io_runner_.get());
98
99 // Create and start our controller thread.
100 base::Thread::Options controller_thread_options;
101 controller_thread_options.message_loop_type =
102 base::MessageLoop::TYPE_CUSTOM;
103 controller_thread_options.message_pump_factory =
104 base::Bind(&common::MessagePumpMojo::Create);
105 CHECK(controller_thread_.StartWithOptions(controller_thread_options));
106 controller_runner_ = controller_thread_.message_loop_proxy().get();
107 CHECK(controller_runner_.get());
108
109 // TODO(vtl): This should be SLAVE, not NONE.
110 embedder::InitIPCSupport(embedder::ProcessType::NONE, controller_runner_,
111 this, io_runner_,
112 embedder::ScopedPlatformHandle());
113 }
114
115 void Shutdown() {
116 Blocker blocker;
117 shutdown_unblocker_ = blocker.GetUnblocker();
118 controller_runner_->PostTask(
119 FROM_HERE, base::Bind(&AppContext::ShutdownOnControllerThread,
120 base::Unretained(this)));
121 blocker.Block();
122 }
123
124 base::SingleThreadTaskRunner* io_runner() const { return io_runner_.get(); }
125
126 base::SingleThreadTaskRunner* controller_runner() const {
127 return controller_runner_.get();
128 }
129
130 ChildControllerImpl* controller() const { return controller_.get(); }
131
132 void set_controller(scoped_ptr<ChildControllerImpl> controller) {
133 controller_ = controller.Pass();
134 }
135
136 private:
137 void ShutdownOnControllerThread() {
138 // First, destroy the controller.
139 controller_.reset();
140
141 // Next shutdown IPC. We'll unblock the main thread in OnShutdownComplete().
142 embedder::ShutdownIPCSupport();
143 }
144
145 // ProcessDelegate implementation.
146 void OnShutdownComplete() override {
147 shutdown_unblocker_.Unblock(base::Closure());
148 }
149
150 base::Thread io_thread_;
151 scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
152
153 base::Thread controller_thread_;
154 scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
155
156 // Accessed only on the controller thread.
157 scoped_ptr<ChildControllerImpl> controller_;
158
159 // Used to unblock the main thread on shutdown.
160 Blocker::Unblocker shutdown_unblocker_;
161
162 DISALLOW_COPY_AND_ASSIGN(AppContext);
163 };
164
165 // ChildControllerImpl ---------------------------------------------------------
166
167 class ChildControllerImpl : public ChildController, public ErrorHandler {
168 public:
169 ~ChildControllerImpl() override {
170 DCHECK(thread_checker_.CalledOnValidThread());
171
172 // TODO(vtl): Pass in the result from |MainMain()|.
173 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED);
174 }
175
176 // To be executed on the controller thread. Creates the |ChildController|,
177 // etc.
178 static void Init(AppContext* app_context,
179 embedder::ScopedPlatformHandle platform_channel,
180 const Blocker::Unblocker& unblocker) {
181 DCHECK(app_context);
182 DCHECK(platform_channel.is_valid());
183
184 DCHECK(!app_context->controller());
185
186 scoped_ptr<ChildControllerImpl> impl(
187 new ChildControllerImpl(app_context, unblocker));
188
189 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
190 platform_channel.Pass(), app_context->io_runner(),
191 base::Bind(&ChildControllerImpl::DidCreateChannel,
192 base::Unretained(impl.get())),
193 base::MessageLoopProxy::current()));
194
195 impl->Bind(host_message_pipe.Pass());
196
197 app_context->set_controller(impl.Pass());
198 }
199
200 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); }
201
202 // |ErrorHandler| methods:
203 void OnConnectionError() override {
204 // A connection error means the connection to the shell is lost. This is not
205 // recoverable.
206 LOG(ERROR) << "Connection error to the shell.";
207 _exit(1);
208 }
209
210 // |ChildController| methods:
211 void StartApp(const String& app_path,
212 bool clean_app_path,
213 InterfaceRequest<Application> application_request,
214 const StartAppCallback& on_app_complete) override {
215 DVLOG(2) << "ChildControllerImpl::StartApp(" << app_path << ", ...)";
216 DCHECK(thread_checker_.CalledOnValidThread());
217
218 on_app_complete_ = on_app_complete;
219 unblocker_.Unblock(base::Bind(&ChildControllerImpl::StartAppOnMainThread,
220 base::FilePath::FromUTF8Unsafe(app_path),
221 clean_app_path
222 ? NativeApplicationCleanup::DELETE
223 : NativeApplicationCleanup::DONT_DELETE,
224 base::Passed(&application_request)));
225 }
226
227 void ExitNow(int32_t exit_code) override {
228 DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")";
229 _exit(exit_code);
230 }
231
232 private:
233 ChildControllerImpl(AppContext* app_context,
234 const Blocker::Unblocker& unblocker)
235 : app_context_(app_context),
236 unblocker_(unblocker),
237 channel_info_(nullptr),
238 binding_(this) {
239 binding_.set_error_handler(this);
240 }
241
242 // Callback for |embedder::CreateChannel()|.
243 void DidCreateChannel(embedder::ChannelInfo* channel_info) {
244 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()";
245 DCHECK(thread_checker_.CalledOnValidThread());
246 channel_info_ = channel_info;
247 }
248
249 static void StartAppOnMainThread(
250 const base::FilePath& app_path,
251 NativeApplicationCleanup cleanup,
252 InterfaceRequest<Application> application_request) {
253 // TODO(vtl): This is copied from in_process_native_runner.cc.
254 DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
255 << " out of process";
256
257 // We intentionally don't unload the native library as its lifetime is the
258 // same as that of the process.
259 base::NativeLibrary app_library = LoadNativeApplication(app_path, cleanup);
260 RunNativeApplication(app_library, application_request.Pass());
261 }
262
263 base::ThreadChecker thread_checker_;
264 AppContext* const app_context_;
265 Blocker::Unblocker unblocker_;
266 StartAppCallback on_app_complete_;
267
268 embedder::ChannelInfo* channel_info_;
269 Binding<ChildController> binding_;
270
271 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl);
272 };
273
274 } // namespace
275
276 // AppChildProcess -------------------------------------------------------------
277
278 AppChildProcess::AppChildProcess() {
279 }
280
281 AppChildProcess::~AppChildProcess() {
282 }
283
284 void AppChildProcess::Main() {
285 DVLOG(2) << "AppChildProcess::Main()";
286
287 DCHECK(!base::MessageLoop::current());
288
289 AppContext app_context;
290 app_context.Init();
291
292 Blocker blocker;
293 app_context.controller_runner()->PostTask(
294 FROM_HERE,
295 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context),
296 base::Passed(platform_channel()), blocker.GetUnblocker()));
297 // This will block, then run whatever the controller wants.
298 blocker.Block();
299
300 app_context.Shutdown();
301 }
302
303 } // namespace shell
304 } // namespace mojo
OLDNEW
« no previous file with comments | « shell/app_child_process.h ('k') | shell/child_main.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698