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.
5 #include "mojo/shell/app_child_process.h"
8 #include "base/callback_helpers.h"
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/scoped_native_library.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/embedder/embedder.h"
23 #include "mojo/public/cpp/system/core.h"
24 #include "mojo/shell/app_child_process.mojom.h"
31 // Blocker ---------------------------------------------------------------------
33 // Blocks a thread until another thread unblocks it, at which point it unblocks
34 // and runs a closure provided by that thread.
41 void Unblock(base::Closure run_after) {
43 DCHECK(blocker_->run_after_.is_null());
44 blocker_->run_after_ = run_after;
45 blocker_->event_.Signal();
51 Unblocker(Blocker* blocker) : blocker_(blocker) {
57 // Copy and assign allowed.
60 Blocker() : event_(true, false) {}
64 DCHECK(run_after_.is_null());
69 Unblocker GetUnblocker() {
70 return Unblocker(this);
74 base::WaitableEvent event_;
75 base::Closure run_after_;
77 DISALLOW_COPY_AND_ASSIGN(Blocker);
80 // AppContext ------------------------------------------------------------------
82 class AppChildControllerImpl;
84 static void DestroyController(scoped_ptr<AppChildControllerImpl> controller) {
87 // Should be created and initialized on the main thread.
91 : io_thread_("io_thread"),
92 controller_thread_("controller_thread") {}
96 // Initialize Mojo before starting any threads.
99 // Create and start our I/O thread.
100 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
101 CHECK(io_thread_.StartWithOptions(io_thread_options));
102 io_runner_ = io_thread_.message_loop_proxy().get();
105 // Create and start our controller thread.
106 base::Thread::Options controller_thread_options;
107 controller_thread_options.message_loop_type =
108 base::MessageLoop::TYPE_CUSTOM;
109 controller_thread_options.message_pump_factory =
110 base::Bind(&common::MessagePumpMojo::Create);
111 CHECK(controller_thread_.StartWithOptions(controller_thread_options));
112 controller_runner_ = controller_thread_.message_loop_proxy().get();
113 CHECK(controller_runner_);
117 controller_runner_->PostTask(
119 base::Bind(&DestroyController, base::Passed(&controller_)));
122 base::SingleThreadTaskRunner* io_runner() const {
123 return io_runner_.get();
126 base::SingleThreadTaskRunner* controller_runner() const {
127 return controller_runner_.get();
130 AppChildControllerImpl* controller() const {
131 return controller_.get();
134 void set_controller(scoped_ptr<AppChildControllerImpl> controller) {
135 controller_ = controller.Pass();
139 // Accessed only on the controller thread.
140 // IMPORTANT: This must be BEFORE |controller_thread_|, so that the controller
141 // thread gets joined (and thus |controller_| reset) before |controller_| is
143 scoped_ptr<AppChildControllerImpl> controller_;
145 base::Thread io_thread_;
146 scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
148 base::Thread controller_thread_;
149 scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
151 DISALLOW_COPY_AND_ASSIGN(AppContext);
154 // AppChildControllerImpl ------------------------------------------------------
156 class AppChildControllerImpl : public InterfaceImpl<AppChildController> {
158 virtual ~AppChildControllerImpl() {
159 DCHECK(thread_checker_.CalledOnValidThread());
161 // TODO(vtl): Pass in the result from |MainMain()|.
162 if (controller_client_)
163 controller_client_->AppCompleted(MOJO_RESULT_UNIMPLEMENTED);
166 // To be executed on the controller thread. Creates the |AppChildController|,
169 AppContext* app_context,
170 embedder::ScopedPlatformHandle platform_channel,
171 const Blocker::Unblocker& unblocker) {
173 DCHECK(platform_channel.is_valid());
175 DCHECK(!app_context->controller());
177 scoped_ptr<AppChildControllerImpl> impl(
178 new AppChildControllerImpl(app_context, unblocker));
180 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
181 platform_channel.Pass(),
182 app_context->io_runner(),
183 base::Bind(&AppChildControllerImpl::DidCreateChannel,
184 base::Unretained(impl.get())),
185 base::MessageLoopProxy::current()));
187 BindToPipe(impl.get(), host_message_pipe.Pass());
189 app_context->set_controller(impl.Pass());
192 virtual void OnConnectionError() OVERRIDE {
193 // TODO(darin): How should we handle a connection error here?
196 // |AppChildController| methods:
198 virtual void SetClient(AppChildControllerClient* client) OVERRIDE {
199 controller_client_ = client;
202 virtual void StartApp(const String& app_path,
203 ScopedMessagePipeHandle service) OVERRIDE {
204 DVLOG(2) << "AppChildControllerImpl::StartApp("
205 << app_path.To<std::string>() << ", ...)";
206 DCHECK(thread_checker_.CalledOnValidThread());
208 // TODO(darin): Add TypeConverter for FilePath <-> mojo::String.
209 unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
210 base::FilePath::FromUTF8Unsafe(
211 app_path.To<std::string>()),
212 base::Passed(&service)));
216 AppChildControllerImpl(AppContext* app_context,
217 const Blocker::Unblocker& unblocker)
218 : app_context_(app_context),
219 unblocker_(unblocker),
220 controller_client_(NULL),
221 channel_info_(NULL) {
224 // Callback for |embedder::CreateChannel()|.
225 void DidCreateChannel(embedder::ChannelInfo* channel_info) {
226 DVLOG(2) << "AppChildControllerImpl::DidCreateChannel()";
227 DCHECK(thread_checker_.CalledOnValidThread());
228 channel_info_ = channel_info;
231 static void StartAppOnMainThread(const base::FilePath& app_path,
232 ScopedMessagePipeHandle service) {
233 // TODO(vtl): This is copied from in_process_dynamic_service_runner.cc.
234 DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
235 << " out of process";
237 base::ScopedClosureRunner app_deleter(
238 base::Bind(base::IgnoreResult(&base::DeleteFile), app_path, false));
241 base::NativeLibraryLoadError load_error;
242 base::ScopedNativeLibrary app_library(
243 base::LoadNativeLibrary(app_path, &load_error));
244 if (!app_library.is_valid()) {
245 LOG(ERROR) << "Failed to load library (error: " << load_error.ToString()
250 typedef MojoResult (*MojoMainFunction)(MojoHandle);
251 MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
252 app_library.GetFunctionPointer("MojoMain"));
253 if (!main_function) {
254 LOG(ERROR) << "Entrypoint MojoMain not found";
258 // TODO(vtl): Report the result back to our parent process.
259 // |MojoMain()| takes ownership of the service handle.
260 MojoResult result = main_function(service.release().value());
261 if (result < MOJO_RESULT_OK)
262 LOG(ERROR) << "MojoMain returned an error: " << result;
266 base::ThreadChecker thread_checker_;
267 AppContext* const app_context_;
268 Blocker::Unblocker unblocker_;
270 AppChildControllerClient* controller_client_;
271 embedder::ChannelInfo* channel_info_;
273 DISALLOW_COPY_AND_ASSIGN(AppChildControllerImpl);
278 // AppChildProcess -------------------------------------------------------------
280 AppChildProcess::AppChildProcess() {
283 AppChildProcess::~AppChildProcess() {
286 void AppChildProcess::Main() {
287 DVLOG(2) << "AppChildProcess::Main()";
289 AppContext app_context;
293 app_context.controller_runner()->PostTask(
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.
300 app_context.Shutdown();