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