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 "mojo/public/platform/native/gles2_impl_chromium_sync_point_thunks.h"
     13 #include "mojo/public/platform/native/gles2_impl_chromium_texture_mailbox_thunks.h"
     14 #include "mojo/public/platform/native/gles2_impl_thunks.h"
     15 #include "mojo/public/platform/native/gles2_thunks.h"
     16 #include "mojo/public/platform/native/system_thunks.h"
     17 
     18 namespace mojo {
     19 namespace shell {
     20 
     21 namespace {
     22 
     23 template <typename Thunks>
     24 bool SetThunks(Thunks (*make_thunks)(),
     25                const char* function_name,
     26                base::ScopedNativeLibrary* library) {
     27   typedef size_t (*SetThunksFn)(const Thunks* thunks);
     28   SetThunksFn set_thunks =
     29       reinterpret_cast<SetThunksFn>(library->GetFunctionPointer(function_name));
     30   if (!set_thunks)
     31     return false;
     32   Thunks thunks = make_thunks();
     33   size_t expected_size = set_thunks(&thunks);
     34   if (expected_size > sizeof(Thunks)) {
     35     LOG(ERROR) << "Invalid app library: expected " << function_name
     36                << " to return thunks of size: " << expected_size;
     37     return false;
     38   }
     39   return true;
     40 }
     41 }
     42 
     43 InProcessDynamicServiceRunner::InProcessDynamicServiceRunner(
     44     Context* context) {
     45 }
     46 
     47 InProcessDynamicServiceRunner::~InProcessDynamicServiceRunner() {
     48   if (thread_) {
     49     DCHECK(thread_->HasBeenStarted());
     50     DCHECK(!thread_->HasBeenJoined());
     51     thread_->Join();
     52   }
     53 
     54   // It is important to let the thread exit before unloading the DSO because
     55   // the library may have registered thread-local data and destructors to run
     56   // on thread termination.
     57   app_library_.Reset(base::NativeLibrary());
     58 }
     59 
     60 void InProcessDynamicServiceRunner::Start(
     61     const base::FilePath& app_path,
     62     ScopedMessagePipeHandle service_handle,
     63     const base::Closure& app_completed_callback) {
     64   app_path_ = app_path;
     65 
     66   DCHECK(!service_handle_.is_valid());
     67   service_handle_ = service_handle.Pass();
     68 
     69   DCHECK(app_completed_callback_runner_.is_null());
     70   app_completed_callback_runner_ = base::Bind(&base::TaskRunner::PostTask,
     71                                               base::MessageLoopProxy::current(),
     72                                               FROM_HERE,
     73                                               app_completed_callback);
     74 
     75   DCHECK(!thread_);
     76   thread_.reset(new base::DelegateSimpleThread(this, "app_thread"));
     77   thread_->Start();
     78 }
     79 
     80 void InProcessDynamicServiceRunner::Run() {
     81   DVLOG(2) << "Loading/running Mojo app in process from library: "
     82            << app_path_.value();
     83 
     84   do {
     85     base::NativeLibraryLoadError error;
     86     app_library_.Reset(base::LoadNativeLibrary(app_path_, &error));
     87     if (!app_library_.is_valid()) {
     88       LOG(ERROR) << "Failed to load app library (error: " << error.ToString()
     89                  << ")";
     90       break;
     91     }
     92 
     93     if (!SetThunks(
     94             &MojoMakeSystemThunks, "MojoSetSystemThunks", &app_library_)) {
     95       // In the component build, Mojo Apps link against mojo_system_impl.
     96 #if !defined(COMPONENT_BUILD)
     97       // Strictly speaking this is not required, but it's very unusual to have
     98       // an app that doesn't require the basic system library.
     99       LOG(WARNING) << "MojoSetSystemThunks not found in app library";
    100 #endif
    101     }
    102 
    103     if (SetThunks(&MojoMakeGLES2ControlThunks,
    104                   "MojoSetGLES2ControlThunks",
    105                   &app_library_)) {
    106       // If we have the control thunks, we probably also have the
    107       // GLES2 implementation thunks.
    108       if (!SetThunks(&MojoMakeGLES2ImplThunks,
    109                      "MojoSetGLES2ImplThunks",
    110                      &app_library_)) {
    111         // In the component build, Mojo Apps link against mojo_gles2_impl.
    112 #if !defined(COMPONENT_BUILD)
    113         // Warn on this really weird case: The library requires the GLES2
    114         // control functions, but doesn't require the GLES2 implementation.
    115         LOG(WARNING) << app_path_.value()
    116                      << " has MojoSetGLES2ControlThunks, "
    117                         "but doesn't have MojoSetGLES2ImplThunks.";
    118 #endif
    119       }
    120 
    121       // If the application is using GLES2 extension points, register those
    122       // thunks. Applications may use or not use any of these, so don't warn if
    123       // they are missing.
    124       SetThunks(MojoMakeGLES2ImplChromiumTextureMailboxThunks,
    125                 "MojoSetGLES2ImplChromiumTextureMailboxThunks",
    126                 &app_library_);
    127       SetThunks(MojoMakeGLES2ImplChromiumSyncPointThunks,
    128                 "MojoSetGLES2ImplChromiumSyncPointThunks",
    129                 &app_library_);
    130     }
    131     // Unlike system thunks, we don't warn on a lack of GLES2 thunks because
    132     // not everything is a visual app.
    133 
    134     typedef MojoResult (*MojoMainFunction)(MojoHandle);
    135     MojoMainFunction main_function = reinterpret_cast<MojoMainFunction>(
    136         app_library_.GetFunctionPointer("MojoMain"));
    137     if (!main_function) {
    138       LOG(ERROR) << "Entrypoint MojoMain not found: " << app_path_.value();
    139       break;
    140     }
    141 
    142     // |MojoMain()| takes ownership of the service handle.
    143     MojoResult result = main_function(service_handle_.release().value());
    144     if (result < MOJO_RESULT_OK)
    145       LOG(ERROR) << "MojoMain returned an error: " << result;
    146   } while (false);
    147 
    148   app_completed_callback_runner_.Run();
    149   app_completed_callback_runner_.Reset();
    150 }
    151 
    152 }  // namespace shell
    153 }  // namespace mojo
    154