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/in_process_dynamic_service_runner.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "base/location.h"
     10 #include "base/logging.h"
     11 #include "base/message_loop/message_loop_proxy.h"
     12 #include "base/scoped_native_library.h"
     13 #include "mojo/public/platform/native/system_thunks.h"
     14 
     15 namespace mojo {
     16 namespace shell {
     17 
     18 InProcessDynamicServiceRunner::InProcessDynamicServiceRunner(
     19     Context* context)
     20     : keep_alive_(context),
     21       thread_(this, "app_thread") {
     22 }
     23 
     24 InProcessDynamicServiceRunner::~InProcessDynamicServiceRunner() {
     25   if (thread_.HasBeenStarted()) {
     26     DCHECK(!thread_.HasBeenJoined());
     27     thread_.Join();
     28   }
     29 }
     30 
     31 void InProcessDynamicServiceRunner::Start(
     32     const base::FilePath& app_path,
     33     ScopedMessagePipeHandle service_handle,
     34     const base::Closure& app_completed_callback) {
     35   app_path_ = app_path;
     36 
     37   DCHECK(!service_handle_.is_valid());
     38   service_handle_ = service_handle.Pass();
     39 
     40   DCHECK(app_completed_callback_runner_.is_null());
     41   app_completed_callback_runner_ = base::Bind(&base::TaskRunner::PostTask,
     42                                               base::MessageLoopProxy::current(),
     43                                               FROM_HERE,
     44                                               app_completed_callback);
     45 
     46   DCHECK(!thread_.HasBeenStarted());
     47   thread_.Start();
     48 }
     49 
     50 void InProcessDynamicServiceRunner::Run() {
     51   DVLOG(2) << "Loading/running Mojo app in process from library: "
     52            << app_path_.value();
     53 
     54   do {
     55     base::NativeLibraryLoadError error;
     56     base::ScopedNativeLibrary app_library(
     57         base::LoadNativeLibrary(app_path_, &error));
     58     if (!app_library.is_valid()) {
     59       LOG(ERROR) << "Failed to load app library (error: " << error.ToString()
     60                  << ")";
     61       break;
     62     }
     63 
     64     MojoSetSystemThunksFn mojo_set_system_thunks_fn =
     65         reinterpret_cast<MojoSetSystemThunksFn>(app_library.GetFunctionPointer(
     66             "MojoSetSystemThunks"));
     67     if (mojo_set_system_thunks_fn) {
     68       MojoSystemThunks system_thunks = MojoMakeSystemThunks();
     69       size_t expected_size = mojo_set_system_thunks_fn(&system_thunks);
     70       if (expected_size > sizeof(MojoSystemThunks)) {
     71         LOG(ERROR)
     72             << "Invalid app library: expected MojoSystemThunks size: "
     73             << expected_size;
     74         break;
     75       }
     76     } else {
     77       // Strictly speaking this is not required, but it's very unusual to have
     78       // an app that doesn't require the basic system library.
     79       LOG(WARNING) << "MojoSetSystemThunks not found in app library";
     80     }
     81 
     82     typedef MojoResult (*MojoMainFunction)(MojoHandle);
     83     MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
     84         app_library.GetFunctionPointer("MojoMain"));
     85     if (!main_function) {
     86       LOG(ERROR) << "Entrypoint MojoMain not found";
     87       break;
     88     }
     89 
     90     // |MojoMain()| takes ownership of the service handle.
     91     MojoResult result = main_function(service_handle_.release().value());
     92     if (result < MOJO_RESULT_OK)
     93       LOG(ERROR) << "MojoMain returned an error: " << result;
     94   } while (false);
     95 
     96   bool success = app_completed_callback_runner_.Run();
     97   app_completed_callback_runner_.Reset();
     98   LOG_IF(ERROR, !success) << "Failed post run app_completed_callback";
     99 }
    100 
    101 }  // namespace shell
    102 }  // namespace mojo
    103