Merge "Add option to enable clang Asan build." into tizen
[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
172         if (!standalone && pluginPreload)
173                 pluginPreload();
174
175         return 0;
176 }
177
178 bool CoreRuntime::initializeCoreClr(const char* appId,
179                                                                          const char* assemblyProbePaths,
180                                                                          const char* pinvokeProbePaths,
181                                                                          const char* tpaList)
182 {
183         const char *propertyKeys[] = {
184                 "TRUSTED_PLATFORM_ASSEMBLIES",
185                 "APP_PATHS",
186                 "APP_NI_PATHS",
187                 "NATIVE_DLL_SEARCH_DIRECTORIES",
188                 "AppDomainCompatSwitch"
189         };
190
191         const char *propertyValues[] = {
192                 tpaList,
193                 assemblyProbePaths,
194                 assemblyProbePaths,
195                 pinvokeProbePaths,
196                 "UseLatestBehaviorWhenTFMNotSpecified"
197         };
198
199         std::string selfPath = readSelfPath();
200
201         int st = initializeClr(selfPath.c_str(),
202                                                         appId,
203                                                         sizeof(propertyKeys) / sizeof(propertyKeys[0]),
204                                                         propertyKeys,
205                                                         propertyValues,
206                                                         &__hostHandle,
207                                                         &__domainId);
208
209         if (st < 0) {
210                 _ERR("initialize core clr fail! (0x%08x)", st);
211                 return false;
212         }
213
214         if (pluginSetCoreclrInfo)
215                 pluginSetCoreclrInfo(__hostHandle, __domainId);
216
217         _DBG("Initialize core clr success");
218         return true;
219 }
220
221 int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList)
222 {
223         if (fileNotExist(__launcherAssembly)) {
224                 _ERR("Launcher assembly is not exist in %s", __launcherAssembly.c_str());
225                 return 1;
226         }
227
228         if (!initializeCoreClr(appId, appBase, appBase, tpaList)) {
229                 _ERR("Failed to initialize coreclr");
230                 return 1;
231         }
232
233 #ifdef USE_MANAGED_LAUNCHER
234         void *preparedFunctionDelegate;
235         int st = createDelegate(__hostHandle, __domainId,
236                                                         "Tizen.Runtime",
237                                                         "Tizen.Runtime.Coreclr.AssemblyManager",
238                                                         "Prepared", &preparedFunctionDelegate);
239         if (st < 0) {
240                 _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
241                 return 1;
242         }
243         preparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
244
245         if (preparedFunction != nullptr)
246                 preparedFunction();
247
248         void *launchFunctionDelegate;
249         st = createDelegate(__hostHandle, __domainId,
250                                                 "Tizen.Runtime",
251                                                 "Tizen.Runtime.Coreclr.AssemblyManager",
252                                                 "Launch", &launchFunctionDelegate);
253         if (st < 0) {
254                 _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
255                 return 1;
256         }
257         launchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
258 #endif
259         return 0;
260 }
261
262 void CoreRuntime::dispose()
263 {
264         if (__hostHandle != nullptr) {
265                 int st = shutdown(__hostHandle, __domainId);
266                 if (st < 0)
267                         _ERR("shutdown core clr fail! (0x%08x)", st);
268         }
269
270         if (dlclose(__coreclrLib) != 0)
271                 _ERR("libcoreclr.so close failed");
272
273         __coreclrLib = nullptr;
274
275         if (pluginFinalize)
276                 pluginFinalize();
277
278         if (__pluginLib != nullptr) {
279                 if (dlclose(__pluginLib) != 0)
280                         _ERR("libdotnet_plugin.so close failed");
281
282                 __pluginLib = nullptr;
283                 pluginInitialize = nullptr;
284                 pluginPreload = nullptr;
285                 pluginSetAppInfo = nullptr;
286                 pluginSetCoreclrInfo = nullptr;
287                 pluginGetDllPath = nullptr;
288                 pluginBeforeExecute = nullptr;
289                 pluginFinalize = nullptr;
290         }
291
292         _DBG("Dotnet runtime disposed");
293 }
294
295 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
296 {
297         if (path == nullptr) {
298                 _ERR("executable path is null");
299                 return 1;
300         }
301
302         if (fileNotExist(path)) {
303                 _ERR("File not exist : %s", path);
304                 return 1;
305         }
306
307         if (pluginSetAppInfo)
308                 pluginSetAppInfo(appId, path);
309
310         std::string tpa;
311         std::string appRoot = root;
312         std::string appBin = concatPath(appRoot, "bin");
313         std::string appLib = concatPath(appRoot, "lib");
314         std::string probePath = appBin + ":" + appLib + ":" + __nativeLibDirectory;
315
316         std::vector<std::string> searchDirectories;
317         searchDirectories.push_back(appBin);
318         searchDirectories.push_back(appLib);
319         if (pluginGetDllPath) {
320                 std::string pluginPath = pluginGetDllPath();
321                 if (!pluginPath.empty()) {
322                         probePath = probePath + ":" + pluginPath;
323                         searchDirectories.push_back(pluginPath);
324                 }
325         }
326         searchDirectories.push_back(__runtimeDirectory);
327         searchDirectories.push_back(__deviceAPIDirectory);
328         searchDirectories.push_back(__refAPIDirectory);
329 #ifdef USE_MANAGED_LAUNCHER
330         searchDirectories.push_back(baseName(__launcherAssembly));
331 #endif
332
333         assembliesInDirectory(searchDirectories, tpa);
334
335         if (pluginBeforeExecute)
336                 pluginBeforeExecute();
337
338         if (runLoggingThread() < 0) {
339                 _ERR("Failed to create logging thread");
340         }
341
342 #ifdef USE_MANAGED_LAUNCHER
343         runManagedLauncher(appId, probePath.c_str(), tpa.c_str());
344
345         bool success = false;
346         if (launchFunction != nullptr) {
347                 success = launchFunction(root, path, argc, argv);
348                 if (!success)
349                         _ERR("Failed to launch Application %s", path);
350                 return success ? 0 : 1;
351         } else {
352                 _ERR("Failed to find launch function");
353                 return 1;
354         }
355 #else
356         int st = initializeCoreClr(appId, probePath.c_str(), probePath.c_str(), tpa.c_str());
357         unsigned int ret = 0;
358         st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
359         if (st < 0)
360                 _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
361         return ret;
362 #endif
363 }
364
365 }  // namespace dotnetcore
366 }  // namespace runtime
367 }  // namespace tizen