add plugin api to set coreclr info
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / dotnet / dotnet_launcher.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <dlfcn.h>
19
20 #include <string>
21 #include <fstream>
22 #include <vector>
23
24 #include "utils.h"
25 #include "log.h"
26 #include "launcher.h"
27 #include "dotnet_launcher.h"
28
29 #define PLUGIN_PATH "/usr/share/dotnet.tizen/lib/libdotnet_plugin.so"
30
31 namespace tizen {
32 namespace runtime {
33 namespace dotnetcore {
34
35 CoreRuntime::CoreRuntime() :
36         initializeClr(nullptr),
37         executeAssembly(nullptr),
38         shutdown(nullptr),
39         createDelegate(nullptr),
40         __coreclrLib(nullptr),
41         __hostHandle(nullptr),
42         __domainId(-1),
43         preparedFunction(nullptr),
44         launchFunction(nullptr),
45         __pluginLib(nullptr),
46         pluginInitialize(nullptr),
47         pluginPreload(nullptr),
48         pluginSetAppInfo(nullptr),
49         pluginSetCoreclrInfo(nullptr),
50         pluginGetDllPath(nullptr),
51         pluginBeforeExecute(nullptr),
52         pluginFinalize(nullptr)
53 {
54 #define __XSTR(x) #x
55 #define __STR(x) __XSTR(x)
56
57 #ifdef DEVICE_API_DIR
58         __deviceAPIDirectory = __STR(DEVICE_API_DIR);
59 #endif
60 #ifdef RUNTIME_DIR
61         __runtimeDirectory = __STR(RUNTIME_DIR);
62 #endif
63 #ifdef NATIVE_LIB_DIR
64         __nativeLibDirectory = __STR(NATIVE_LIB_DIR);
65 #endif
66
67 #ifdef USE_MANAGED_LAUNCHER
68 #ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH
69         __launcherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH);
70 #endif
71 #endif
72
73 #undef __STR
74 #undef __XSTR
75
76         // support launcher plugin
77         if (!fileNotExist(PLUGIN_PATH)) {
78                 __pluginLib = dlopen(PLUGIN_PATH, RTLD_NOW | RTLD_LOCAL);
79                 if (__pluginLib) {
80                         pluginInitialize  = (plugin_initialize_ptr)dlsym(__pluginLib, "plugin_initialize");
81                         pluginPreload  = (plugin_preload_ptr)dlsym(__pluginLib, "plugin_preload");
82                         pluginSetAppInfo  = (plugin_set_app_info_ptr)dlsym(__pluginLib, "plugin_set_app_info");
83                         pluginSetCoreclrInfo = (plugin_set_coreclr_info_ptr)dlsym(__pluginLib, "plugin_set_coreclr_info");
84                         pluginGetDllPath  = (plugin_get_dll_path_ptr)dlsym(__pluginLib, "plugin_get_dll_path");
85                         pluginBeforeExecute  = (plugin_before_execute_ptr)dlsym(__pluginLib, "plugin_before_execute");
86                         pluginFinalize  = (plugin_finalize_ptr)dlsym(__pluginLib, "plugin_finalize");
87                 }
88         }
89
90         if (pluginInitialize)
91                 pluginInitialize();
92
93         _DBG("Constructor called!!");
94 }
95
96 CoreRuntime::~CoreRuntime()
97 {
98         dispose();
99 }
100
101 int CoreRuntime::initialize(bool standalone)
102 {
103 #ifdef __arm__
104         // libunwind library is used to unwind stack frame, but libunwind for ARM
105         // does not support ARM vfpv3/NEON registers in DWARF format correctly.
106         // Therefore let's disable stack unwinding using DWARF information
107         // See https://github.com/dotnet/coreclr/issues/6698
108         //
109         // libunwind use following methods to unwind stack frame.
110         // UNW_ARM_METHOD_ALL          0xFF
111         // UNW_ARM_METHOD_DWARF        0x01
112         // UNW_ARM_METHOD_FRAME        0x02
113         // UNW_ARM_METHOD_EXIDX        0x04
114         putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
115 #endif // __arm__
116
117         if (__deviceAPIDirectory.empty()) {
118                 _ERR("Empty Device API Directory");
119                 return 1;
120         } else {
121                 __deviceAPIDirectory = absolutePath(__deviceAPIDirectory);
122         }
123
124         if (__runtimeDirectory.empty()) {
125                 _ERR("Empty Runtime Directory");
126                 return 1;
127         } else {
128                 __runtimeDirectory = absolutePath(__runtimeDirectory);
129         }
130
131         // set Reference API directory
132         __refAPIDirectory = __deviceAPIDirectory + "/ref";
133
134 #ifdef USE_MANAGED_LAUNCHER
135         if (__launcherAssembly.empty()) {
136                 _ERR("Empty Launcher Assembly");
137                 return 1;
138         } else {
139                 __launcherAssembly = absolutePath(__launcherAssembly);
140         }
141 #endif
142
143         std::string libCoreclr(concatPath(__runtimeDirectory, "libcoreclr.so"));
144
145         _DBG("libcoreclr : %s", libCoreclr.c_str());
146
147         __coreclrLib = dlopen(libCoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
148         if (__coreclrLib == nullptr) {
149                 char *err = dlerror();
150                 _ERR("dlopen failed to open libcoreclr.so with error %s", err);
151                 return 1;
152         }
153
154 #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
155         do { \
156                 variable = (type)dlsym(__coreclrLib, name); \
157                 if (variable == nullptr) { \
158                         _ERR(name " is not found in the libcoreclr.so"); \
159                         return 1; \
160                 } \
161         } while (0)
162
163         CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, initializeClr, "coreclr_initialize");
164         CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, executeAssembly, "coreclr_execute_assembly");
165         CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, shutdown, "coreclr_shutdown");
166         CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, createDelegate, "coreclr_create_delegate");
167
168 #undef CORELIB_RETURN_IF_NOSYM
169
170         _DBG("libcoreclr dlopen and dlsym success");
171         _DBG("this addr : %x", this);
172         _DBG("coreclr_initialize : %x", initializeClr);
173
174         if (!standalone && pluginPreload)
175                 pluginPreload();
176
177         return 0;
178 }
179
180 bool CoreRuntime::initializeCoreClr(const char* appId,
181                                                                          const char* assemblyProbePaths,
182                                                                          const char* pinvokeProbePaths,
183                                                                          const char* tpaList)
184 {
185         const char *propertyKeys[] = {
186                 "TRUSTED_PLATFORM_ASSEMBLIES",
187                 "APP_PATHS",
188                 "APP_NI_PATHS",
189                 "NATIVE_DLL_SEARCH_DIRECTORIES",
190                 "AppDomainCompatSwitch"
191         };
192
193         const char *propertyValues[] = {
194                 tpaList,
195                 assemblyProbePaths,
196                 assemblyProbePaths,
197                 pinvokeProbePaths,
198                 "UseLatestBehaviorWhenTFMNotSpecified"
199         };
200
201         std::string selfPath = readSelfPath();
202
203         int st = initializeClr(selfPath.c_str(),
204                                                         appId,
205                                                         sizeof(propertyKeys) / sizeof(propertyKeys[0]),
206                                                         propertyKeys,
207                                                         propertyValues,
208                                                         &__hostHandle,
209                                                         &__domainId);
210
211         if (st < 0) {
212                 _ERR("initialize core clr fail! (0x%08x)", st);
213                 return false;
214         }
215
216         if (pluginSetCoreclrInfo)
217                 pluginSetCoreclrInfo(__hostHandle, __domainId);
218
219         _DBG("Initialize core clr success");
220         return true;
221 }
222
223 int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList)
224 {
225         if (fileNotExist(__launcherAssembly)) {
226                 _ERR("Launcher assembly is not exist in %s", __launcherAssembly.c_str());
227                 return 1;
228         }
229
230         if (!initializeCoreClr(appId, appBase, appBase, tpaList)) {
231                 _ERR("Failed to initialize coreclr");
232                 return 1;
233         }
234
235 #ifdef USE_MANAGED_LAUNCHER
236         void *preparedFunctionDelegate;
237         int st = createDelegate(__hostHandle, __domainId,
238                                                         "Tizen.Runtime",
239                                                         "Tizen.Runtime.Coreclr.AssemblyManager",
240                                                         "Prepared", &preparedFunctionDelegate);
241         if (st < 0) {
242                 _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
243                 return 1;
244         }
245         preparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
246
247         if (preparedFunction != nullptr)
248                 preparedFunction();
249
250         void *launchFunctionDelegate;
251         st = createDelegate(__hostHandle, __domainId,
252                                                 "Tizen.Runtime",
253                                                 "Tizen.Runtime.Coreclr.AssemblyManager",
254                                                 "Launch", &launchFunctionDelegate);
255         if (st < 0) {
256                 _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
257                 return 1;
258         }
259         launchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
260 #endif
261         return 0;
262 }
263
264 void CoreRuntime::dispose()
265 {
266         if (__hostHandle != nullptr) {
267                 int st = shutdown(__hostHandle, __domainId);
268                 if (st < 0)
269                         _ERR("shutdown core clr fail! (0x%08x)", st);
270         }
271
272         if (dlclose(__coreclrLib) != 0)
273                 _ERR("libcoreclr.so close failed");
274
275         __coreclrLib = nullptr;
276
277         if (pluginFinalize)
278                 pluginFinalize();
279
280         if (__pluginLib != nullptr) {
281                 if (dlclose(__pluginLib) != 0)
282                         _ERR("libdotnet_plugin.so close failed");
283
284                 __pluginLib = nullptr;
285                 pluginInitialize = nullptr;
286                 pluginPreload = nullptr;
287                 pluginSetAppInfo = nullptr;
288                 pluginSetCoreclrInfo = nullptr;
289                 pluginGetDllPath = nullptr;
290                 pluginBeforeExecute = nullptr;
291                 pluginFinalize = nullptr;
292         }
293
294         _DBG("Dotnet runtime disposed");
295 }
296
297 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
298 {
299         if (path == nullptr) {
300                 _ERR("executable path is null");
301                 return 1;
302         }
303
304         if (fileNotExist(path)) {
305                 _ERR("File not exist : %s", path);
306                 return 1;
307         }
308
309         if (pluginSetAppInfo)
310                 pluginSetAppInfo(appId, path);
311
312         std::string tpa;
313         std::string appRoot = root;
314         std::string appBin = concatPath(appRoot, "bin");
315         std::string appLib = concatPath(appRoot, "lib");
316         std::string probePath = appBin + ":" + appLib + ":" + __nativeLibDirectory;
317
318         std::vector<std::string> searchDirectories;
319         searchDirectories.push_back(appBin);
320         searchDirectories.push_back(appLib);
321         if (pluginGetDllPath) {
322                 std::string pluginPath = pluginGetDllPath();
323                 if (!pluginPath.empty()) {
324                         probePath = probePath + ":" + pluginPath;
325                         searchDirectories.push_back(pluginPath);
326                 }
327         }
328         searchDirectories.push_back(__runtimeDirectory);
329         searchDirectories.push_back(__deviceAPIDirectory);
330         searchDirectories.push_back(__refAPIDirectory);
331 #ifdef USE_MANAGED_LAUNCHER
332         searchDirectories.push_back(baseName(__launcherAssembly));
333 #endif
334
335         assembliesInDirectory(searchDirectories, tpa);
336
337         if (pluginBeforeExecute)
338                 pluginBeforeExecute();
339
340 #ifdef USE_MANAGED_LAUNCHER
341         runManagedLauncher(appId, probePath.c_str(), tpa.c_str());
342
343         bool success = false;
344         if (launchFunction != nullptr) {
345                 std::string cppPath(path);
346
347                 if (isManagedAssembly(cppPath) && !isNativeImage(cppPath)) {
348                         size_t extindex = cppPath.size() - 4;
349                         cppPath = cppPath.substr(0, extindex) + ".ni" + cppPath.substr(extindex, 4);
350                         if (!fileNotExist(cppPath))
351                                 path = cppPath.c_str();
352                 }
353
354                 success = launchFunction(root, path, argc, argv);
355                 if (!success)
356                         _ERR("Failed to launch Application %s", path);
357                 return success ? 0 : 1;
358         } else {
359                 _ERR("Failed to find launch function");
360                 return 1;
361         }
362 #else
363         int st = initializeCoreClr(appId, probePath.c_str(), probePath.c_str(), tpa.c_str());
364         unsigned int ret = 0;
365         st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
366         if (st < 0)
367                 _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
368         return ret;
369 #endif
370 }
371
372 }  // namespace dotnetcore
373 }  // namespace runtime
374 }  // namespace tizen