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