Home | History | Annotate | Download | only in shell
      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
    293