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