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/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:
     38     ~Unblocker() {}
     39 
     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;
     50     Unblocker(Blocker* blocker) : blocker_(blocker) {
     51       DCHECK(blocker_);
     52     }
     53 
     54     Blocker* blocker_;
     55 
     56     // Copy and assign allowed.
     57   };
     58 
     59   Blocker() : event_(true, false) {}
     60   ~Blocker() {}
     61 
     62   void Block() {
     63     DCHECK(run_after_.is_null());
     64     event_.Wait();
     65     run_after_.Run();
     66   }
     67 
     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 
     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:
     89   AppContext()
     90       : io_thread_("io_thread"),
     91         controller_thread_("controller_thread") {}
     92   ~AppContext() {}
     93 
     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 
    115   void Shutdown() {
    116     controller_runner_->PostTask(
    117         FROM_HERE,
    118         base::Bind(&DestroyController, base::Passed(&controller_)));
    119   }
    120 
    121   base::SingleThreadTaskRunner* io_runner() const {
    122     return io_runner_.get();
    123   }
    124 
    125   base::SingleThreadTaskRunner* controller_runner() const {
    126     return controller_runner_.get();
    127   }
    128 
    129   AppChildControllerImpl* controller() const {
    130     return controller_.get();
    131   }
    132 
    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:
    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.
    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 
    190   virtual void OnConnectionError() OVERRIDE {
    191     // TODO(darin): How should we handle a connection error here?
    192   }
    193 
    194   // |AppChildController| methods:
    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:
    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()|.
    214   void DidCreateChannel(embedder::ChannelInfo* channel_info) {
    215     DVLOG(2) << "AppChildControllerImpl::DidCreateChannel()";
    216     DCHECK(thread_checker_.CalledOnValidThread());
    217     channel_info_ = channel_info;
    218   }
    219 
    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 
    265 AppChildProcess::AppChildProcess() {
    266 }
    267 
    268 AppChildProcess::~AppChildProcess() {
    269 }
    270 
    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