Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / mojo / runner / child_process.cc
blobf5adb3030db70160cd4c0831752d760129085111
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/runner/child_process.h"
7 #include "base/base_switches.h"
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/command_line.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/thread_task_runner_handle.h"
21 #include "base/threading/thread.h"
22 #include "base/threading/thread_checker.h"
23 #include "base/thread_task_runner_handle.h"
24 #include "mojo/common/message_pump_mojo.h"
25 #include "mojo/edk/embedder/embedder.h"
26 #include "mojo/edk/embedder/platform_channel_pair.h"
27 #include "mojo/edk/embedder/process_delegate.h"
28 #include "mojo/edk/embedder/scoped_platform_handle.h"
29 #include "mojo/edk/embedder/simple_platform_support.h"
30 #include "mojo/public/cpp/system/core.h"
31 #include "mojo/runner/child_process.mojom.h"
32 #include "mojo/runner/native_application_support.h"
33 #include "mojo/runner/switches.h"
35 namespace mojo {
36 namespace runner {
38 namespace {
40 // Blocker ---------------------------------------------------------------------
42 // Blocks a thread until another thread unblocks it, at which point it unblocks
43 // and runs a closure provided by that thread.
44 class Blocker {
45 public:
46 class Unblocker {
47 public:
48 explicit Unblocker(Blocker* blocker = nullptr) : blocker_(blocker) {}
49 ~Unblocker() {}
51 void Unblock(base::Closure run_after) {
52 DCHECK(blocker_);
53 DCHECK(blocker_->run_after_.is_null());
54 blocker_->run_after_ = run_after;
55 blocker_->event_.Signal();
56 blocker_ = nullptr;
59 private:
60 Blocker* blocker_;
62 // Copy and assign allowed.
65 Blocker() : event_(true, false) {}
66 ~Blocker() {}
68 void Block() {
69 DCHECK(run_after_.is_null());
70 event_.Wait();
71 if (!run_after_.is_null())
72 run_after_.Run();
75 Unblocker GetUnblocker() { return Unblocker(this); }
77 private:
78 base::WaitableEvent event_;
79 base::Closure run_after_;
81 DISALLOW_COPY_AND_ASSIGN(Blocker);
84 // AppContext ------------------------------------------------------------------
86 class ChildControllerImpl;
88 // Should be created and initialized on the main thread.
89 class AppContext : public embedder::ProcessDelegate {
90 public:
91 AppContext()
92 : io_thread_("io_thread"), controller_thread_("controller_thread") {}
93 ~AppContext() override {}
95 void Init() {
96 // Initialize Mojo before starting any threads.
97 embedder::Init(make_scoped_ptr(new embedder::SimplePlatformSupport()));
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_.task_runner().get();
103 CHECK(io_runner_.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_.task_runner().get();
113 CHECK(controller_runner_.get());
115 // TODO(vtl): This should be SLAVE, not NONE.
116 embedder::InitIPCSupport(embedder::ProcessType::NONE, controller_runner_,
117 this, io_runner_,
118 embedder::ScopedPlatformHandle());
121 void Shutdown() {
122 Blocker blocker;
123 shutdown_unblocker_ = blocker.GetUnblocker();
124 controller_runner_->PostTask(
125 FROM_HERE, base::Bind(&AppContext::ShutdownOnControllerThread,
126 base::Unretained(this)));
127 blocker.Block();
130 base::SingleThreadTaskRunner* io_runner() const { return io_runner_.get(); }
132 base::SingleThreadTaskRunner* controller_runner() const {
133 return controller_runner_.get();
136 ChildControllerImpl* controller() const { return controller_.get(); }
138 void set_controller(scoped_ptr<ChildControllerImpl> controller) {
139 controller_ = controller.Pass();
142 private:
143 void ShutdownOnControllerThread() {
144 // First, destroy the controller.
145 controller_.reset();
147 // Next shutdown IPC. We'll unblock the main thread in OnShutdownComplete().
148 embedder::ShutdownIPCSupport();
151 // ProcessDelegate implementation.
152 void OnShutdownComplete() override {
153 shutdown_unblocker_.Unblock(base::Closure());
156 base::Thread io_thread_;
157 scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
159 base::Thread controller_thread_;
160 scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
162 // Accessed only on the controller thread.
163 scoped_ptr<ChildControllerImpl> controller_;
165 // Used to unblock the main thread on shutdown.
166 Blocker::Unblocker shutdown_unblocker_;
168 DISALLOW_COPY_AND_ASSIGN(AppContext);
171 // ChildControllerImpl ------------------------------------------------------
173 class ChildControllerImpl : public ChildController {
174 public:
175 ~ChildControllerImpl() override {
176 DCHECK(thread_checker_.CalledOnValidThread());
178 // TODO(vtl): Pass in the result from |MainMain()|.
179 on_app_complete_.Run(MOJO_RESULT_UNIMPLEMENTED);
182 // To be executed on the controller thread. Creates the |ChildController|,
183 // etc.
184 static void Init(AppContext* app_context,
185 embedder::ScopedPlatformHandle platform_channel,
186 const Blocker::Unblocker& unblocker) {
187 DCHECK(app_context);
188 DCHECK(platform_channel.is_valid());
190 DCHECK(!app_context->controller());
192 scoped_ptr<ChildControllerImpl> impl(
193 new ChildControllerImpl(app_context, unblocker));
195 ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
196 platform_channel.Pass(),
197 base::Bind(&ChildControllerImpl::DidCreateChannel,
198 base::Unretained(impl.get())),
199 base::ThreadTaskRunnerHandle::Get()));
201 impl->Bind(host_message_pipe.Pass());
203 app_context->set_controller(impl.Pass());
206 void Bind(ScopedMessagePipeHandle handle) { binding_.Bind(handle.Pass()); }
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);
215 // |ChildController| methods:
216 void StartApp(const String& app_path,
217 bool clean_app_path,
218 InterfaceRequest<Application> application_request,
219 const StartAppCallback& on_app_complete) override {
220 DVLOG(2) << "ChildControllerImpl::StartApp(" << app_path << ", ...)";
221 DCHECK(thread_checker_.CalledOnValidThread());
223 on_app_complete_ = on_app_complete;
224 unblocker_.Unblock(base::Bind(
225 &ChildControllerImpl::StartAppOnMainThread,
226 base::FilePath::FromUTF8Unsafe(app_path),
227 clean_app_path ? shell::NativeApplicationCleanup::DELETE
228 : shell::NativeApplicationCleanup::DONT_DELETE,
229 base::Passed(&application_request)));
232 void ExitNow(int32_t exit_code) override {
233 DVLOG(2) << "ChildControllerImpl::ExitNow(" << exit_code << ")";
234 _exit(exit_code);
237 private:
238 ChildControllerImpl(AppContext* app_context,
239 const Blocker::Unblocker& unblocker)
240 : app_context_(app_context),
241 unblocker_(unblocker),
242 channel_info_(nullptr),
243 binding_(this) {
244 binding_.set_connection_error_handler([this]() { OnConnectionError(); });
247 // Callback for |embedder::CreateChannel()|.
248 void DidCreateChannel(embedder::ChannelInfo* channel_info) {
249 DVLOG(2) << "ChildControllerImpl::DidCreateChannel()";
250 DCHECK(thread_checker_.CalledOnValidThread());
251 channel_info_ = channel_info;
254 static void StartAppOnMainThread(
255 const base::FilePath& app_path,
256 shell::NativeApplicationCleanup cleanup,
257 InterfaceRequest<Application> application_request) {
258 // TODO(vtl): This is copied from in_process_native_runner.cc.
259 DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
260 << " out of process";
262 // We intentionally don't unload the native library as its lifetime is the
263 // same as that of the process.
264 base::NativeLibrary app_library = LoadNativeApplication(app_path, cleanup);
265 RunNativeApplication(app_library, application_request.Pass());
268 base::ThreadChecker thread_checker_;
269 AppContext* const app_context_;
270 Blocker::Unblocker unblocker_;
271 StartAppCallback on_app_complete_;
273 embedder::ChannelInfo* channel_info_;
274 Binding<ChildController> binding_;
276 DISALLOW_COPY_AND_ASSIGN(ChildControllerImpl);
279 } // namespace
281 int ChildProcessMain() {
282 DVLOG(2) << "ChildProcessMain()";
283 const base::CommandLine& command_line =
284 *base::CommandLine::ForCurrentProcess();
285 embedder::ScopedPlatformHandle platform_channel =
286 embedder::PlatformChannelPair::PassClientHandleFromParentProcess(
287 command_line);
288 CHECK(platform_channel.is_valid());
290 DCHECK(!base::MessageLoop::current());
292 AppContext app_context;
293 app_context.Init();
295 Blocker blocker;
296 app_context.controller_runner()->PostTask(
297 FROM_HERE,
298 base::Bind(&ChildControllerImpl::Init, base::Unretained(&app_context),
299 base::Passed(&platform_channel), blocker.GetUnblocker()));
300 // This will block, then run whatever the controller wants.
301 blocker.Block();
303 app_context.Shutdown();
305 return 0;
308 } // namespace runner
309 } // namespace mojo