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

Side by Side Diff: mojo/shell/child_process.cc

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

Powered by Google App Engine
This is Rietveld 408576698