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