6adff4b09a01dd0c46a6b18db5e89f6fe2d4411d
[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         _DBG("this addr : %x", this);
170         _DBG("coreclr_initialize : %x", initializeClr);
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         _DBG("Initialize core clr success");
215         return true;
216 }
217
218 int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList)
219 {
220         if (fileNotExist(__launcherAssembly)) {
221                 _ERR("Launcher assembly is not exist in %s", __launcherAssembly.c_str());
222                 return 1;
223         }
224
225         if (!initializeCoreClr(appId, appBase, appBase, tpaList)) {
226                 _ERR("Failed to initialize coreclr");
227                 return 1;
228         }
229
230 #ifdef USE_MANAGED_LAUNCHER
231         void *preparedFunctionDelegate;
232         int st = createDelegate(__hostHandle, __domainId,
233                                                         "Tizen.Runtime",
234                                                         "Tizen.Runtime.Coreclr.AssemblyManager",
235                                                         "Prepared", &preparedFunctionDelegate);
236         if (st < 0) {
237                 _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
238                 return 1;
239         }
240         preparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
241
242         if (preparedFunction != nullptr)
243                 preparedFunction();
244
245         void *launchFunctionDelegate;
246         st = createDelegate(__hostHandle, __domainId,
247                                                 "Tizen.Runtime",
248                                                 "Tizen.Runtime.Coreclr.AssemblyManager",
249                                                 "Launch", &launchFunctionDelegate);
250         if (st < 0) {
251                 _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
252                 return 1;
253         }
254         launchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
255 #endif
256         return 0;
257 }
258
259 void CoreRuntime::dispose()
260 {
261         if (__hostHandle != nullptr) {
262                 int st = shutdown(__hostHandle, __domainId);
263                 if (st < 0)
264                         _ERR("shutdown core clr fail! (0x%08x)", st);
265         }
266
267         if (dlclose(__coreclrLib) != 0)
268                 _ERR("libcoreclr.so close failed");
269
270         __coreclrLib = nullptr;
271
272         if (pluginFinalize)
273                 pluginFinalize();
274
275         if (__pluginLib != nullptr) {
276                 if (dlclose(__pluginLib) != 0)
277                         _ERR("libdotnet_plugin.so close failed");
278
279                 __pluginLib = nullptr;
280                 pluginInitialize = nullptr;
281                 pluginPreload = nullptr;
282                 pluginSetAppInfo = nullptr;
283                 pluginGetDllPath = nullptr;
284                 pluginBeforeExecute = nullptr;
285                 pluginFinalize = nullptr;
286         }
287
288         _DBG("Dotnet runtime disposed");
289 }
290
291 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
292 {
293         if (path == nullptr) {
294                 _ERR("executable path is null");
295                 return 1;
296         }
297
298         if (fileNotExist(path)) {
299                 _ERR("File not exist : %s", path);
300                 return 1;
301         }
302
303         if (pluginSetAppInfo)
304                 pluginSetAppInfo(appId, path);
305
306         std::string tpa;
307         std::string appRoot = root;
308         std::string appBin = concatPath(appRoot, "bin");
309         std::string appLib = concatPath(appRoot, "lib");
310         std::string probePath = appBin + ":" + appLib + ":" + __nativeLibDirectory;
311
312         std::vector<std::string> searchDirectories;
313         searchDirectories.push_back(appBin);
314         searchDirectories.push_back(appLib);
315         if (pluginGetDllPath) {
316                 std::string pluginPath = pluginGetDllPath();
317                 if (!pluginPath.empty()) {
318                         probePath = probePath + ":" + pluginPath;
319                         searchDirectories.push_back(pluginPath);
320                 }
321         }
322         searchDirectories.push_back(__runtimeDirectory);
323         searchDirectories.push_back(__deviceAPIDirectory);
324         searchDirectories.push_back(__refAPIDirectory);
325 #ifdef USE_MANAGED_LAUNCHER
326         searchDirectories.push_back(baseName(__launcherAssembly));
327 #endif
328
329         assembliesInDirectory(searchDirectories, tpa);
330
331         if (pluginBeforeExecute)
332                 pluginBeforeExecute();
333
334 #ifdef USE_MANAGED_LAUNCHER
335         runManagedLauncher(appId, probePath.c_str(), tpa.c_str());
336
337         bool success = false;
338         if (launchFunction != nullptr) {
339                 std::string cppPath(path);
340
341                 if (isManagedAssembly(cppPath) && !isNativeImage(cppPath)) {
342                         size_t extindex = cppPath.size() - 4;
343                         cppPath = cppPath.substr(0, extindex) + ".ni" + cppPath.substr(extindex, 4);
344                         if (!fileNotExist(cppPath))
345                                 path = cppPath.c_str();
346                 }
347
348                 success = launchFunction(root, path, argc, argv);
349                 if (!success)
350                         _ERR("Failed to launch Application %s", path);
351                 return success ? 0 : 1;
352         } else {
353                 _ERR("Failed to find launch function");
354                 return 1;
355         }
356 #else
357         int st = initializeCoreClr(appId, probePath.c_str(), probePath.c_str(), tpa.c_str());
358         unsigned int ret = 0;
359         st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
360         if (st < 0)
361                 _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
362         return ret;
363 #endif
364 }
365
366 }  // namespace dotnetcore
367 }  // namespace runtime
368 }  // namespace tizen