Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / mojo / shell / app_child_process.cc
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 "mojo/shell/app_child_process.h"
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/files/file_path.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.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/embedder/simple_platform_support.h"
24 #include "mojo/public/cpp/system/core.h"
25 #include "mojo/shell/app_child_process.mojom.h"
26
27 namespace mojo {
28 namespace shell {
29
30 namespace {
31
32 // Blocker ---------------------------------------------------------------------
33
34 // Blocks a thread until another thread unblocks it, at which point it unblocks
35 // and runs a closure provided by that thread.
36 class Blocker {
37  public:
38   class Unblocker {
39    public:
40     ~Unblocker() {}
41
42     void Unblock(base::Closure run_after) {
43       DCHECK(blocker_);
44       DCHECK(blocker_->run_after_.is_null());
45       blocker_->run_after_ = run_after;
46       blocker_->event_.Signal();
47       blocker_ = NULL;
48     }
49
50    private:
51     friend class Blocker;
52     Unblocker(Blocker* blocker) : blocker_(blocker) {
53       DCHECK(blocker_);
54     }
55
56     Blocker* blocker_;
57
58     // Copy and assign allowed.
59   };
60
61   Blocker() : event_(true, false) {}
62   ~Blocker() {}
63
64   void Block() {
65     DCHECK(run_after_.is_null());
66     event_.Wait();
67     run_after_.Run();
68   }
69
70   Unblocker GetUnblocker() {
71     return Unblocker(this);
72   }
73
74  private:
75   base::WaitableEvent event_;
76   base::Closure run_after_;
77
78   DISALLOW_COPY_AND_ASSIGN(Blocker);
79 };
80
81 // AppContext ------------------------------------------------------------------
82
83 class AppChildControllerImpl;
84
85 static void DestroyController(scoped_ptr<AppChildControllerImpl> controller) {
86 }
87
88 // Should be created and initialized on the main thread.
89 class AppContext {
90  public:
91   AppContext()
92       : io_thread_("io_thread"),
93         controller_thread_("controller_thread") {}
94   ~AppContext() {}
95
96   void Init() {
97     // Initialize Mojo before starting any threads.
98     embedder::Init(scoped_ptr<mojo::embedder::PlatformSupport>(
99         new mojo::embedder::SimplePlatformSupport()));
100
101     // Create and start our I/O thread.
102     base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
103     CHECK(io_thread_.StartWithOptions(io_thread_options));
104     io_runner_ = io_thread_.message_loop_proxy().get();
105     CHECK(io_runner_.get());
106
107     // Create and start our controller thread.
108     base::Thread::Options controller_thread_options;
109     controller_thread_options.message_loop_type =
110         base::MessageLoop::TYPE_CUSTOM;
111     controller_thread_options.message_pump_factory =
112         base::Bind(&common::MessagePumpMojo::Create);
113     CHECK(controller_thread_.StartWithOptions(controller_thread_options));
114     controller_runner_ = controller_thread_.message_loop_proxy().get();
115     CHECK(controller_runner_.get());
116   }
117
118   void Shutdown() {
119     controller_runner_->PostTask(
120         FROM_HERE,
121         base::Bind(&DestroyController, base::Passed(&controller_)));
122   }
123
124   base::SingleThreadTaskRunner* io_runner() const {
125     return io_runner_.get();
126   }
127
128   base::SingleThreadTaskRunner* controller_runner() const {
129     return controller_runner_.get();
130   }
131
132   AppChildControllerImpl* controller() const {
133     return controller_.get();
134   }
135
136   void set_controller(scoped_ptr<AppChildControllerImpl> controller) {
137     controller_ = controller.Pass();
138   }
139
140  private:
141   // Accessed only on the controller thread.
142   // IMPORTANT: This must be BEFORE |controller_thread_|, so that the controller
143   // thread gets joined (and thus |controller_| reset) before |controller_| is
144   // destroyed.
145   scoped_ptr<AppChildControllerImpl> controller_;
146
147   base::Thread io_thread_;
148   scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
149
150   base::Thread controller_thread_;
151   scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
152
153   DISALLOW_COPY_AND_ASSIGN(AppContext);
154 };
155
156 // AppChildControllerImpl ------------------------------------------------------
157
158 class AppChildControllerImpl : public InterfaceImpl<AppChildController> {
159  public:
160   virtual ~AppChildControllerImpl() {
161     DCHECK(thread_checker_.CalledOnValidThread());
162
163     // TODO(vtl): Pass in the result from |MainMain()|.
164     client()->AppCompleted(MOJO_RESULT_UNIMPLEMENTED);
165   }
166
167   // To be executed on the controller thread. Creates the |AppChildController|,
168   // etc.
169   static void Init(
170       AppContext* app_context,
171       embedder::ScopedPlatformHandle platform_channel,
172       const Blocker::Unblocker& unblocker) {
173     DCHECK(app_context);
174     DCHECK(platform_channel.is_valid());
175
176     DCHECK(!app_context->controller());
177
178     scoped_ptr<AppChildControllerImpl> impl(
179         new AppChildControllerImpl(app_context, unblocker));
180
181     ScopedMessagePipeHandle host_message_pipe(embedder::CreateChannel(
182         platform_channel.Pass(),
183         app_context->io_runner(),
184         base::Bind(&AppChildControllerImpl::DidCreateChannel,
185                    base::Unretained(impl.get())),
186         base::MessageLoopProxy::current()));
187
188     BindToPipe(impl.get(), host_message_pipe.Pass());
189
190     app_context->set_controller(impl.Pass());
191   }
192
193   virtual void OnConnectionError() OVERRIDE {
194     // TODO(darin): How should we handle a connection error here?
195   }
196
197   // |AppChildController| methods:
198   virtual void StartApp(const String& app_path,
199                         ScopedMessagePipeHandle service) OVERRIDE {
200     DVLOG(2) << "AppChildControllerImpl::StartApp(" << app_path << ", ...)";
201     DCHECK(thread_checker_.CalledOnValidThread());
202
203     unblocker_.Unblock(base::Bind(&AppChildControllerImpl::StartAppOnMainThread,
204                                   base::FilePath::FromUTF8Unsafe(app_path),
205                                   base::Passed(&service)));
206   }
207
208  private:
209   AppChildControllerImpl(AppContext* app_context,
210                          const Blocker::Unblocker& unblocker)
211       : app_context_(app_context),
212         unblocker_(unblocker),
213         channel_info_(NULL) {
214   }
215
216   // Callback for |embedder::CreateChannel()|.
217   void DidCreateChannel(embedder::ChannelInfo* channel_info) {
218     DVLOG(2) << "AppChildControllerImpl::DidCreateChannel()";
219     DCHECK(thread_checker_.CalledOnValidThread());
220     channel_info_ = channel_info;
221   }
222
223   static void StartAppOnMainThread(const base::FilePath& app_path,
224                                    ScopedMessagePipeHandle service) {
225     // TODO(vtl): This is copied from in_process_dynamic_service_runner.cc.
226     DVLOG(2) << "Loading/running Mojo app from " << app_path.value()
227              << " out of process";
228
229     do {
230       base::NativeLibraryLoadError load_error;
231       base::ScopedNativeLibrary app_library(
232           base::LoadNativeLibrary(app_path, &load_error));
233       if (!app_library.is_valid()) {
234         LOG(ERROR) << "Failed to load library (error: " << load_error.ToString()
235                    << ")";
236         break;
237       }
238
239       typedef MojoResult (*MojoMainFunction)(MojoHandle);
240       MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
241           app_library.GetFunctionPointer("MojoMain"));
242       if (!main_function) {
243         LOG(ERROR) << "Entrypoint MojoMain not found";
244         break;
245       }
246
247       // TODO(vtl): Report the result back to our parent process.
248       // |MojoMain()| takes ownership of the service handle.
249       MojoResult result = main_function(service.release().value());
250       if (result < MOJO_RESULT_OK)
251         LOG(ERROR) << "MojoMain returned an error: " << result;
252     } while (false);
253   }
254
255   base::ThreadChecker thread_checker_;
256   AppContext* const app_context_;
257   Blocker::Unblocker unblocker_;
258
259   embedder::ChannelInfo* channel_info_;
260
261   DISALLOW_COPY_AND_ASSIGN(AppChildControllerImpl);
262 };
263
264 }  // namespace
265
266 // AppChildProcess -------------------------------------------------------------
267
268 AppChildProcess::AppChildProcess() {
269 }
270
271 AppChildProcess::~AppChildProcess() {
272 }
273
274 void AppChildProcess::Main() {
275   DVLOG(2) << "AppChildProcess::Main()";
276
277   AppContext app_context;
278   app_context.Init();
279
280   Blocker blocker;
281   app_context.controller_runner()->PostTask(
282       FROM_HERE,
283       base::Bind(&AppChildControllerImpl::Init, base::Unretained(&app_context),
284                  base::Passed(platform_channel()), blocker.GetUnblocker()));
285   // This will block, then run whatever the controller wants.
286   blocker.Block();
287
288   app_context.Shutdown();
289 }
290
291 }  // namespace shell
292 }  // namespace mojo