support launcher plugin
[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 (standalone) {
116                 const char *deviceApiDirectory = getenv("__deviceAPIDirectory");
117                 const char *runtimeDirectory = getenv("__runtimeDirectory");
118                 if (deviceApiDirectory != nullptr)
119                         __deviceAPIDirectory = deviceApiDirectory;
120                 if (runtimeDirectory != nullptr)
121                         __runtimeDirectory = runtimeDirectory;
122
123 #ifdef USE_MANAGED_LAUNCHER
124                 const char *launcherAssembly = getenv("__launcherAssembly");
125                 if (launcherAssembly != nullptr)
126                         __launcherAssembly = launcherAssembly;
127 #endif
128         }
129
130         if (__deviceAPIDirectory.empty()) {
131                 _ERR("Empty Device API Directory");
132                 return 1;
133         } else {
134                 __deviceAPIDirectory = absolutePath(__deviceAPIDirectory);
135         }
136
137         if (__runtimeDirectory.empty()) {
138                 _ERR("Empty Runtime Directory");
139                 return 1;
140         } else {
141                 __runtimeDirectory = absolutePath(__runtimeDirectory);
142         }
143
144         // set Reference API directory
145         __refAPIDirectory = __deviceAPIDirectory + "/ref";
146
147 #ifdef USE_MANAGED_LAUNCHER
148         if (__launcherAssembly.empty()) {
149                 _ERR("Empty Launcher Assembly");
150                 return 1;
151         } else {
152                 __launcherAssembly = absolutePath(__launcherAssembly);
153         }
154 #endif
155
156         std::string libCoreclr(concatPath(__runtimeDirectory, "libcoreclr.so"));
157
158         _DBG("libcoreclr : %s", libCoreclr.c_str());
159
160         __coreclrLib = dlopen(libCoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
161         if (__coreclrLib == nullptr) {
162                 char *err = dlerror();
163                 _ERR("dlopen failed to open libcoreclr.so with error %s", err);
164                 return 1;
165         }
166
167 #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
168         do { \
169                 variable = (type)dlsym(__coreclrLib, name); \
170                 if (variable == nullptr) { \
171                         _ERR(name " is not found in the libcoreclr.so"); \
172                         return 1; \
173                 } \
174         } while (0)
175
176         CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, initializeClr, "coreclr_initialize");
177         CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, executeAssembly, "coreclr_execute_assembly");
178         CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, shutdown, "coreclr_shutdown");
179         CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, createDelegate, "coreclr_create_delegate");
180
181 #undef CORELIB_RETURN_IF_NOSYM
182
183         _DBG("libcoreclr dlopen and dlsym success");
184         _DBG("this addr : %x", this);
185         _DBG("coreclr_initialize : %x", initializeClr);
186
187         if (!standalone && pluginPreload)
188                 pluginPreload();
189
190         return 0;
191 }
192
193 bool CoreRuntime::initializeCoreClr(const char* appId,
194                                                                          const char* assemblyProbePaths,
195                                                                          const char* pinvokeProbePaths,
196                                                                          const char* tpaList)
197 {
198         const char *propertyKeys[] = {
199                 "TRUSTED_PLATFORM_ASSEMBLIES",
200                 "APP_PATHS",
201                 "APP_NI_PATHS",
202                 "NATIVE_DLL_SEARCH_DIRECTORIES",
203                 "AppDomainCompatSwitch"
204         };
205
206         const char *propertyValues[] = {
207                 tpaList,
208                 assemblyProbePaths,
209                 assemblyProbePaths,
210                 pinvokeProbePaths,
211                 "UseLatestBehaviorWhenTFMNotSpecified"
212         };
213
214         std::string selfPath = readSelfPath();
215
216         int st = initializeClr(selfPath.c_str(),
217                                                         appId,
218                                                         sizeof(propertyKeys) / sizeof(propertyKeys[0]),
219                                                         propertyKeys,
220                                                         propertyValues,
221                                                         &__hostHandle,
222                                                         &__domainId);
223
224         if (st < 0) {
225                 _ERR("initialize core clr fail! (0x%08x)", st);
226                 return false;
227         }
228
229         _DBG("Initialize core clr success");
230         return true;
231 }
232
233 int CoreRuntime::runManagedLauncher(const char* appId, const char* appBase, const char* tpaList)
234 {
235         if (fileNotExist(__launcherAssembly)) {
236                 _ERR("Launcher assembly is not exist in %s", __launcherAssembly.c_str());
237                 return 1;
238         }
239
240         if (!initializeCoreClr(appId, appBase, appBase, tpaList)) {
241                 _ERR("Failed to initialize coreclr");
242                 return 1;
243         }
244
245 #ifdef USE_MANAGED_LAUNCHER
246         void *preparedFunctionDelegate;
247         int st = createDelegate(__hostHandle, __domainId,
248                                                         "Tizen.Runtime",
249                                                         "Tizen.Runtime.Coreclr.AssemblyManager",
250                                                         "Prepared", &preparedFunctionDelegate);
251         if (st < 0) {
252                 _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
253                 return 1;
254         }
255         preparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
256
257         if (preparedFunction != nullptr)
258                 preparedFunction();
259
260         void *launchFunctionDelegate;
261         st = createDelegate(__hostHandle, __domainId,
262                                                 "Tizen.Runtime",
263                                                 "Tizen.Runtime.Coreclr.AssemblyManager",
264                                                 "Launch", &launchFunctionDelegate);
265         if (st < 0) {
266                 _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
267                 return 1;
268         }
269         launchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
270 #endif
271         return 0;
272 }
273
274 void CoreRuntime::dispose()
275 {
276         if (__hostHandle != nullptr) {
277                 int st = shutdown(__hostHandle, __domainId);
278                 if (st < 0)
279                         _ERR("shutdown core clr fail! (0x%08x)", st);
280         }
281
282         if (dlclose(__coreclrLib) != 0)
283                 _ERR("libcoreclr.so close failed");
284
285         __coreclrLib = nullptr;
286
287         if (pluginFinalize)
288                 pluginFinalize();
289
290         if (__pluginLib != nullptr) {
291                 if (dlclose(__pluginLib) != 0)
292                         _ERR("libdotnet_plugin.so close failed");
293
294                 __pluginLib = nullptr;
295                 pluginInitialize = nullptr;
296                 pluginPreload = nullptr;
297                 pluginSetAppInfo = nullptr;
298                 pluginGetDllPath = nullptr;
299                 pluginBeforeExecute = nullptr;
300                 pluginFinalize = nullptr;
301         }
302
303         _DBG("Dotnet runtime disposed");
304 }
305
306 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
307 {
308         if (path == nullptr) {
309                 _ERR("executable path is null");
310                 return 1;
311         }
312
313         if (fileNotExist(path)) {
314                 _ERR("File not exist : %s", path);
315                 return 1;
316         }
317
318         if (pluginSetAppInfo)
319                 pluginSetAppInfo(appId, path);
320
321         std::string tpa;
322         std::string appRoot = root;
323         std::string appBin = concatPath(appRoot, "bin");
324         std::string appLib = concatPath(appRoot, "lib");
325         std::string probePath = appBin + ":" + appLib + ":" + __nativeLibDirectory;
326
327         std::vector<std::string> searchDirectories;
328         searchDirectories.push_back(appBin);
329         searchDirectories.push_back(appLib);
330         if (pluginGetDllPath) {
331                 std::string pluginPath = pluginGetDllPath();
332                 if (!pluginPath.empty()) {
333                         probePath = probePath + ":" + pluginPath;
334                         searchDirectories.push_back(pluginPath);
335                 }
336         }
337         searchDirectories.push_back(__runtimeDirectory);
338         searchDirectories.push_back(__deviceAPIDirectory);
339         searchDirectories.push_back(__refAPIDirectory);
340 #ifdef USE_MANAGED_LAUNCHER
341         searchDirectories.push_back(baseName(__launcherAssembly));
342 #endif
343
344         assembliesInDirectory(searchDirectories, tpa);
345
346         if (pluginBeforeExecute)
347                 pluginBeforeExecute();
348
349 #ifdef USE_MANAGED_LAUNCHER
350         runManagedLauncher(appId, probePath.c_str(), tpa.c_str());
351
352         bool success = false;
353         if (launchFunction != nullptr) {
354                 std::string cppPath(path);
355
356                 if (isManagedAssembly(cppPath) && !isNativeImage(cppPath)) {
357                         size_t extindex = cppPath.size() - 4;
358                         cppPath = cppPath.substr(0, extindex) + ".ni" + cppPath.substr(extindex, 4);
359                         if (!fileNotExist(cppPath))
360                                 path = cppPath.c_str();
361                 }
362
363                 success = launchFunction(root, path, argc, argv);
364                 if (!success)
365                         _ERR("Failed to launch Application %s", path);
366                 return success ? 0 : 1;
367         } else {
368                 _ERR("Failed to find launch function");
369                 return 1;
370         }
371 #else
372         int st = initializeCoreClr(appId, probePath.c_str(), probePath.c_str(), tpa.c_str());
373         unsigned int ret = 0;
374         st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
375         if (st < 0)
376                 _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
377         return ret;
378 #endif
379 }
380
381 }  // namespace dotnetcore
382 }  // namespace runtime
383 }  // namespace tizen