Upstream version 7.36.149.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/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"
25
26 namespace mojo {
27 namespace shell {
28
29 namespace {
30
31 // Blocker ---------------------------------------------------------------------
32
33 // Blocks a thread until another thread unblocks it, at which point it unblocks
34 // and runs a closure provided by that thread.
35 class Blocker {
36  public:
37   class Unblocker {
38    public:
39     ~Unblocker() {}
40
41     void Unblock(base::Closure run_after) {
42       DCHECK(blocker_);
43       DCHECK(blocker_->run_after_.is_null());
44       blocker_->run_after_ = run_after;
45       blocker_->event_.Signal();
46       blocker_ = NULL;
47     }
48
49    private:
50     friend class Blocker;
51     Unblocker(Blocker* blocker) : blocker_(blocker) {
52       DCHECK(blocker_);
53     }
54
55     Blocker* blocker_;
56
57     // Copy and assign allowed.
58   };
59
60   Blocker() : event_(true, false) {}
61   ~Blocker() {}
62
63   void Block() {
64     DCHECK(run_after_.is_null());
65     event_.Wait();
66     run_after_.Run();
67   }
68
69   Unblocker GetUnblocker() {
70     return Unblocker(this);
71   }
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 static void DestroyController(scoped_ptr<AppChildControllerImpl> controller) {
85 }
86
87 // Should be created and initialized on the main thread.
88 class AppContext {
89  public:
90   AppContext()
91       : io_thread_("io_thread"),
92         controller_thread_("controller_thread") {}
93   ~AppContext() {}
94
95   void Init() {
96     // Initialize Mojo before starting any threads.
97     embedder::Init();
98
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();
103     CHECK(io_runner_);
104
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_);
114   }
115
116   void Shutdown() {
117     controller_runner_->PostTask(
118         FROM_HERE,
119         base::Bind(&DestroyController, base::Passed(&controller_)));
120   }
121
122   base::SingleThreadTaskRunner* io_runner() const {
123     return io_runner_.get();
124   }
125
126   base::SingleThreadTaskRunner* controller_runner() const {
127     return controller_runner_.get();
128   }
129
130   AppChildControllerImpl* controller() const {
131     return controller_.get();
132   }
133
134   void set_controller(scoped_ptr<AppChildControllerImpl> controller) {
135     controller_ = controller.Pass();
136   }
137
138  private:
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
142   // destroyed.
143   scoped_ptr<AppChildControllerImpl> controller_;
144
145   base::Thread io_thread_;
146   scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
147
148   base::Thread controller_thread_;
149   scoped_refptr<base::SingleThreadTaskRunner> controller_runner_;
150
151   DISALLOW_COPY_AND_ASSIGN(AppContext);
152 };
153
154 // AppChildControllerImpl ------------------------------------------------------
155
156 class AppChildControllerImpl : public InterfaceImpl<AppChildController> {
157  public:
158   virtual ~AppChildControllerImpl() {
159     DCHECK(thread_checker_.CalledOnValidThread());
160
161     // TODO(vtl): Pass in the result from |MainMain()|.
162     if (controller_client_)
163       controller_client_->AppCompleted(MOJO_RESULT_UNIMPLEMENTED);
164   }
165
166   // To be executed on the controller thread. Creates the |AppChildController|,
167   // etc.
168   static void Init(
169       AppContext* app_context,
170       embedder::ScopedPlatformHandle platform_channel,
171       const Blocker::Unblocker& unblocker) {
172     DCHECK(app_context);
173     DCHECK(platform_channel.is_valid());
174
175     DCHECK(!app_context->controller());
176
177     scoped_ptr<AppChildControllerImpl> impl(
178         new AppChildControllerImpl(app_context, unblocker));
179
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()));
186
187     BindToPipe(impl.get(), host_message_pipe.Pass());
188
189     app_context->set_controller(impl.Pass());
190   }
191
192   virtual void OnConnectionError() OVERRIDE {
193     // TODO(darin): How should we handle a connection error here?
194   }
195
196   // |AppChildController| methods:
197
198   virtual void SetClient(AppChildControllerClient* client) OVERRIDE {
199     controller_client_ = client;
200   }
201
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());
207
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)));
213   }
214
215  private:
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) {
222   }
223
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;
229   }
230
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";
236
237     base::ScopedClosureRunner app_deleter(
238         base::Bind(base::IgnoreResult(&base::DeleteFile), app_path, false));
239
240     do {
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()
246                    << ")";
247         break;
248       }
249
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";
255         break;
256       }
257
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;
263     } while (false);
264   }
265
266   base::ThreadChecker thread_checker_;
267   AppContext* const app_context_;
268   Blocker::Unblocker unblocker_;
269
270   AppChildControllerClient* controller_client_;
271   embedder::ChannelInfo* channel_info_;
272
273   DISALLOW_COPY_AND_ASSIGN(AppChildControllerImpl);
274 };
275
276 }  // namespace
277
278 // AppChildProcess -------------------------------------------------------------
279
280 AppChildProcess::AppChildProcess() {
281 }
282
283 AppChildProcess::~AppChildProcess() {
284 }
285
286 void AppChildProcess::Main() {
287   DVLOG(2) << "AppChildProcess::Main()";
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
303 }  // namespace shell
304 }  // namespace mojo