blob: 1e3834eb04d50931624015ee1bab9e67630e8900 [file] [log] [blame]
James Robinson646469d2014-10-03 15:33:28 -07001// 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
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -08005#include <unistd.h>
6
Viet-Trung Luue0a4a182015-04-07 16:28:01 -07007#include "base/at_exit.h"
James Robinson646469d2014-10-03 15:33:28 -07008#include "base/bind.h"
9#include "base/callback_helpers.h"
Viet-Trung Luu1e23c672015-04-01 14:46:29 -070010#include "base/command_line.h"
James Robinson646469d2014-10-03 15:33:28 -070011#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"
James Robinson646469d2014-10-03 15:33:28 -070018#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"
Viet-Trung Luu1e23c672015-04-01 14:46:29 -070024#include "mojo/edk/embedder/platform_channel_pair.h"
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -080025#include "mojo/edk/embedder/process_delegate.h"
Viet-Trung Luu1e23c672015-04-01 14:46:29 -070026#include "mojo/edk/embedder/scoped_platform_handle.h"
James Robinson646469d2014-10-03 15:33:28 -070027#include "mojo/edk/embedder/simple_platform_support.h"
28#include "mojo/public/cpp/system/core.h"
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -070029#include "shell/child_controller.mojom.h"
Viet-Trung Luue0a4a182015-04-07 16:28:01 -070030#include "shell/init.h"
Viet-Trung Luue126c862015-03-30 19:20:45 -070031#include "shell/native_application_support.h"
Viet-Trung Luue0a4a182015-04-07 16:28:01 -070032#include "shell/switches.h"
James Robinson646469d2014-10-03 15:33:28 -070033
James Robinson646469d2014-10-03 15:33:28 -070034namespace shell {
James Robinson646469d2014-10-03 15:33:28 -070035namespace {
36
37// Blocker ---------------------------------------------------------------------
38
39// Blocks a thread until another thread unblocks it, at which point it unblocks
40// and runs a closure provided by that thread.
41class Blocker {
42 public:
43 class Unblocker {
44 public:
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -080045 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {}
James Robinson646469d2014-10-03 15:33:28 -070046 ~Unblocker() {}
47
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();
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -080053 blocker_ = nullptr;
James Robinson646469d2014-10-03 15:33:28 -070054 }
55
56 private:
James Robinson646469d2014-10-03 15:33:28 -070057 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();
Viet-Trung Luu26292982015-04-14 18:06:55 -070068 if (!run_after_.is_null())
69 run_after_.Run();
James Robinson646469d2014-10-03 15:33:28 -070070 }
71
James Robinsonb4b7af22014-12-05 11:21:01 -080072 Unblocker GetUnblocker() { return Unblocker(this); }
James Robinson646469d2014-10-03 15:33:28 -070073
74 private:
75 base::WaitableEvent event_;
76 base::Closure run_after_;
77
78 DISALLOW_COPY_AND_ASSIGN(Blocker);
79};
80
81// AppContext ------------------------------------------------------------------
82
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -070083class ChildControllerImpl;
James Robinson646469d2014-10-03 15:33:28 -070084
James Robinson646469d2014-10-03 15:33:28 -070085// Should be created and initialized on the main thread.
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -070086class AppContext : public mojo::embedder::ProcessDelegate {
James Robinson646469d2014-10-03 15:33:28 -070087 public:
88 AppContext()
James Robinsonb4b7af22014-12-05 11:21:01 -080089 : io_thread_("io_thread"), controller_thread_("controller_thread") {}
Dave Moorecc0e4f92015-03-10 15:23:04 -070090 ~AppContext() override {}
James Robinson646469d2014-10-03 15:33:28 -070091
92 void Init() {
93 // Initialize Mojo before starting any threads.
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -070094 mojo::embedder::Init(
95 make_scoped_ptr(new mojo::embedder::SimplePlatformSupport()));
James Robinson646469d2014-10-03 15:33:28 -070096
97 // Create and start our I/O thread.
98 base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
99 CHECK(io_thread_.StartWithOptions(io_thread_options));
100 io_runner_ = io_thread_.message_loop_proxy().get();
101 CHECK(io_runner_.get());
102
103 // Create and start our controller thread.
104 base::Thread::Options controller_thread_options;
105 controller_thread_options.message_loop_type =
106 base::MessageLoop::TYPE_CUSTOM;
107 controller_thread_options.message_pump_factory =
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700108 base::Bind(&mojo::common::MessagePumpMojo::Create);
James Robinson646469d2014-10-03 15:33:28 -0700109 CHECK(controller_thread_.StartWithOptions(controller_thread_options));
110 controller_runner_ = controller_thread_.message_loop_proxy().get();
111 CHECK(controller_runner_.get());
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800112
113 // TODO(vtl): This should be SLAVE, not NONE.
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700114 mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE,
115 controller_runner_, this, io_runner_,
116 mojo::embedder::ScopedPlatformHandle());
James Robinson646469d2014-10-03 15:33:28 -0700117 }
118
119 void Shutdown() {
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800120 Blocker blocker;
121 shutdown_unblocker_ = blocker.GetUnblocker();
James Robinson646469d2014-10-03 15:33:28 -0700122 controller_runner_->PostTask(
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800123 FROM_HERE, base::Bind(&AppContext::ShutdownOnControllerThread,
124 base::Unretained(this)));
125 blocker.Block();
James Robinson646469d2014-10-03 15:33:28 -0700126 }
127
James Robinsonb4b7af22014-12-05 11:21:01 -0800128 base::SingleThreadTaskRunner* io_runner() const { return io_runner_.get(); }
James Robinson646469d2014-10-03 15:33:28 -0700129
130 base::SingleThreadTaskRunner* controller_runner() const {
131 return controller_runner_.get();
132 }
133
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700134 ChildControllerImpl* controller() const { return controller_.get(); }
James Robinson646469d2014-10-03 15:33:28 -0700135
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700136 void set_controller(scoped_ptr<ChildControllerImpl> controller) {
James Robinson646469d2014-10-03 15:33:28 -0700137 controller_ = controller.Pass();
138 }
139
140 private:
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800141 void ShutdownOnControllerThread() {
142 // First, destroy the controller.
143 controller_.reset();
144
145 // Next shutdown IPC. We'll unblock the main thread in OnShutdownComplete().
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700146 mojo::embedder::ShutdownIPCSupport();
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800147 }
148
149 // ProcessDelegate implementation.
150 void OnShutdownComplete() override {
151 shutdown_unblocker_.Unblock(base::Closure());
152 }
James Robinson646469d2014-10-03 15:33:28 -0700153
154 base::Thread io_thread_;
155 scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
156
157 base::Thread controller_thread_;
158 scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
159
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800160 // Accessed only on the controller thread.
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700161 scoped_ptr<ChildControllerImpl> controller_;
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800162
163 // Used to unblock the main thread on shutdown.
164 Blocker::Unblocker shutdown_unblocker_;
165
James Robinson646469d2014-10-03 15:33:28 -0700166 DISALLOW_COPY_AND_ASSIGN(AppContext);
167};
168
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700169// ChildControllerImpl ---------------------------------------------------------
James Robinson646469d2014-10-03 15:33:28 -0700170
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700171class ChildControllerImpl : public ChildController, public mojo::ErrorHandler {
James Robinson646469d2014-10-03 15:33:28 -0700172 public:
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700173 ~ChildControllerImpl() override {
James Robinson646469d2014-10-03 15:33:28 -0700174 DCHECK(thread_checker_.CalledOnValidThread());
175
176 // TODO(vtl): Pass in the result from |MainMain()|.
Benjamin Lermanab0a8dd2015-02-05 12:56:09 +0100177 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED);
James Robinson646469d2014-10-03 15:33:28 -0700178 }
179
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700180 // To be executed on the controller thread. Creates the |ChildController|,
James Robinson646469d2014-10-03 15:33:28 -0700181 // etc.
James Robinsonb4b7af22014-12-05 11:21:01 -0800182 static void Init(AppContext* app_context,
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700183 mojo::embedder::ScopedPlatformHandle platform_channel,
James Robinsonb4b7af22014-12-05 11:21:01 -0800184 const Blocker::Unblocker& unblocker) {
James Robinson646469d2014-10-03 15:33:28 -0700185 DCHECK(app_context);
186 DCHECK(platform_channel.is_valid());
187
188 DCHECK(!app_context->controller());
189
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700190 scoped_ptr<ChildControllerImpl> impl(
191 new ChildControllerImpl(app_context, unblocker));
James Robinson646469d2014-10-03 15:33:28 -0700192
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700193 mojo::ScopedMessagePipeHandle host_message_pipe(
194 mojo::embedder::CreateChannel(
195 platform_channel.Pass(), app_context->io_runner(),
196 base::Bind(&ChildControllerImpl::DidCreateChannel,
197 base::Unretained(impl.get())),
198 base::MessageLoopProxy::current()));
James Robinson646469d2014-10-03 15:33:28 -0700199
James Robinsonf2a87202015-02-12 17:03:49 -0800200 impl->Bind(host_message_pipe.Pass());
James Robinson646469d2014-10-03 15:33:28 -0700201
202 app_context->set_controller(impl.Pass());
203 }
204
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700205 void Bind(mojo::ScopedMessagePipeHandle handle) {
206 binding_.Bind(handle.Pass());
207 }
James Robinsonf2a87202015-02-12 17:03:49 -0800208
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700209 // |mojo::ErrorHandler| methods:
James Robinsone1b30cf2014-10-21 12:25:40 -0700210 void OnConnectionError() override {
Benjamin Lermanab0a8dd2015-02-05 12:56:09 +0100211 // A connection error means the connection to the shell is lost. This is not
212 // recoverable.
Viet-Trung Luuf3e4e332015-03-03 14:11:14 -0800213 LOG(ERROR) << "Connection error to the shell.";
214 _exit(1);
James Robinson646469d2014-10-03 15:33:28 -0700215 }
216
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700217 // |ChildController| methods:
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700218 void StartApp(const mojo::String& app_path,
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700219 mojo::InterfaceRequest<mojo::Application> application_request,
Benjamin Lermanab0a8dd2015-02-05 12:56:09 +0100220 const StartAppCallback& on_app_complete) override {
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700221 DVLOG(2) << "ChildControllerImpl::StartApp(" << app_path << ", ...)";
James Robinson646469d2014-10-03 15:33:28 -0700222 DCHECK(thread_checker_.CalledOnValidThread());
223
Benjamin Lermanab0a8dd2015-02-05 12:56:09 +0100224 on_app_complete_ = on_app_complete;
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700225 unblocker_.Unblock(base::Bind(&ChildControllerImpl::StartAppOnMainThread,
James Robinson646469d2014-10-03 15:33:28 -0700226 base::FilePath::FromUTF8Unsafe(app_path),
James Robinsone5ae9e42015-01-26 17:53:08 -0800227 base::Passed(&application_request)));
James Robinson646469d2014-10-03 15:33:28 -0700228 }
229
Viet-Trung Luu6d948cc2015-03-31 10:48:02 -0700230 void ExitNow(int32_t exit_code) override {
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700231 DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")";
Viet-Trung Luu6d948cc2015-03-31 10:48:02 -0700232 _exit(exit_code);
233 }
234
James Robinson646469d2014-10-03 15:33:28 -0700235 private:
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700236 ChildControllerImpl(AppContext* app_context,
237 const Blocker::Unblocker& unblocker)
James Robinsonf2a87202015-02-12 17:03:49 -0800238 : app_context_(app_context),
239 unblocker_(unblocker),
240 channel_info_(nullptr),
241 binding_(this) {
242 binding_.set_error_handler(this);
243 }
James Robinson646469d2014-10-03 15:33:28 -0700244
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700245 // Callback for |mojo::embedder::CreateChannel()|.
246 void DidCreateChannel(mojo::embedder::ChannelInfo* channel_info) {
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700247 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()";
James Robinson646469d2014-10-03 15:33:28 -0700248 DCHECK(thread_checker_.CalledOnValidThread());
249 channel_info_ = channel_info;
250 }
251
James Robinsone5ae9e42015-01-26 17:53:08 -0800252 static void StartAppOnMainThread(
253 const base::FilePath& app_path,
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700254 mojo::InterfaceRequest<mojo::Application> application_request) {
Viet-Trung Luu47e2e352015-03-04 16:38:18 -0800255 // TODO(vtl): This is copied from in_process_native_runner.cc.
James Robinson646469d2014-10-03 15:33:28 -0700256 DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
257 << " out of process";
258
Dave Moore3a99b932014-10-30 08:38:23 -0700259 // We intentionally don't unload the native library as its lifetime is the
260 // same as that of the process.
Benjamin Lerman5d429aa2015-05-07 16:21:00 +0200261 base::NativeLibrary app_library = LoadNativeApplication(app_path);
Viet-Trung Luue126c862015-03-30 19:20:45 -0700262 RunNativeApplication(app_library, application_request.Pass());
James Robinson646469d2014-10-03 15:33:28 -0700263 }
264
265 base::ThreadChecker thread_checker_;
266 AppContext* const app_context_;
267 Blocker::Unblocker unblocker_;
Benjamin Lermanab0a8dd2015-02-05 12:56:09 +0100268 StartAppCallback on_app_complete_;
James Robinson646469d2014-10-03 15:33:28 -0700269
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700270 mojo::embedder::ChannelInfo* channel_info_;
271 mojo::Binding<ChildController> binding_;
James Robinson646469d2014-10-03 15:33:28 -0700272
Viet-Trung Luuf09c0d92015-04-01 14:38:57 -0700273 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl);
James Robinson646469d2014-10-03 15:33:28 -0700274};
275
276} // namespace
Viet-Trung Luue0a4a182015-04-07 16:28:01 -0700277} // namespace shell
James Robinson646469d2014-10-03 15:33:28 -0700278
Viet-Trung Luue0a4a182015-04-07 16:28:01 -0700279int main(int argc, char** argv) {
280 base::AtExitManager at_exit;
281 base::CommandLine::Init(argc, argv);
James Robinson646469d2014-10-03 15:33:28 -0700282
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700283 shell::InitializeLogging();
Viet-Trung Luu6d948cc2015-03-31 10:48:02 -0700284
Viet-Trung Luue0a4a182015-04-07 16:28:01 -0700285 // Make sure that we're really meant to be invoked as the child process.
286 CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
287 switches::kChildProcess));
288
289 mojo::embedder::ScopedPlatformHandle platform_channel =
290 mojo::embedder::PlatformChannelPair::PassClientHandleFromParentProcess(
Viet-Trung Luu1e23c672015-04-01 14:46:29 -0700291 *base::CommandLine::ForCurrentProcess());
292 CHECK(platform_channel.is_valid());
293
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700294 shell::AppContext app_context;
James Robinson646469d2014-10-03 15:33:28 -0700295 app_context.Init();
296
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700297 shell::Blocker blocker;
James Robinson646469d2014-10-03 15:33:28 -0700298 app_context.controller_runner()->PostTask(
299 FROM_HERE,
Viet-Trung Luubd07e3a2015-04-09 12:43:29 -0700300 base::Bind(&shell::ChildControllerImpl::Init,
Viet-Trung Luue0a4a182015-04-07 16:28:01 -0700301 base::Unretained(&app_context),
Viet-Trung Luu1e23c672015-04-01 14:46:29 -0700302 base::Passed(&platform_channel), blocker.GetUnblocker()));
James Robinson646469d2014-10-03 15:33:28 -0700303 // This will block, then run whatever the controller wants.
304 blocker.Block();
305
306 app_context.Shutdown();
Viet-Trung Luu1e23c672015-04-01 14:46:29 -0700307
308 return 0;
James Robinson646469d2014-10-03 15:33:28 -0700309}