Initialize coreclr in the candidate process and change ON_BOOT value to OFF
[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 <fcntl.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <unistd.h>
29
30 #include "utils.h"
31 #include "log.h"
32 #include "launcher.h"
33 #include "dotnet_launcher.h"
34
35 #define PLUGIN_PATH "/usr/share/dotnet.tizen/lib/libdotnet_plugin.so"
36
37 namespace tizen {
38 namespace runtime {
39 namespace dotnetcore {
40
41 CoreRuntime::CoreRuntime() :
42         initializeClr(nullptr),
43         executeAssembly(nullptr),
44         shutdown(nullptr),
45         createDelegate(nullptr),
46         __coreclrLib(nullptr),
47         __hostHandle(nullptr),
48         __domainId(-1),
49         preparedFunction(nullptr),
50         launchFunction(nullptr),
51         __pluginLib(nullptr),
52         pluginInitialize(nullptr),
53         pluginPreload(nullptr),
54         pluginSetAppInfo(nullptr),
55         pluginSetCoreclrInfo(nullptr),
56         pluginGetDllPath(nullptr),
57         pluginBeforeExecute(nullptr),
58         pluginFinalize(nullptr),
59         fd(0)
60 {
61 #define __XSTR(x) #x
62 #define __STR(x) __XSTR(x)
63
64 #ifdef DEVICE_API_DIR
65         __deviceAPIDirectory = __STR(DEVICE_API_DIR);
66 #endif
67 #ifdef RUNTIME_DIR
68         __runtimeDirectory = __STR(RUNTIME_DIR);
69 #endif
70 #ifdef NATIVE_LIB_DIR
71         __nativeLibDirectory = __STR(NATIVE_LIB_DIR);
72 #endif
73
74 #undef __STR
75 #undef __XSTR
76
77         // support launcher plugin
78         if (!fileNotExist(PLUGIN_PATH)) {
79                 __pluginLib = dlopen(PLUGIN_PATH, RTLD_NOW | RTLD_LOCAL);
80                 if (__pluginLib) {
81                         pluginInitialize  = (plugin_initialize_ptr)dlsym(__pluginLib, "plugin_initialize");
82                         pluginPreload  = (plugin_preload_ptr)dlsym(__pluginLib, "plugin_preload");
83                         pluginSetAppInfo  = (plugin_set_app_info_ptr)dlsym(__pluginLib, "plugin_set_app_info");
84                         pluginSetCoreclrInfo = (plugin_set_coreclr_info_ptr)dlsym(__pluginLib, "plugin_set_coreclr_info");
85                         pluginGetDllPath  = (plugin_get_dll_path_ptr)dlsym(__pluginLib, "plugin_get_dll_path");
86                         pluginBeforeExecute  = (plugin_before_execute_ptr)dlsym(__pluginLib, "plugin_before_execute");
87                         pluginFinalize  = (plugin_finalize_ptr)dlsym(__pluginLib, "plugin_finalize");
88                 }
89         }
90
91         if (pluginInitialize)
92                 pluginInitialize();
93
94         _DBG("Constructor called!!");
95 }
96
97 CoreRuntime::~CoreRuntime()
98 {
99         dispose();
100 }
101
102 int CoreRuntime::initialize(bool standalone)
103 {
104 #ifdef __arm__
105         // libunwind library is used to unwind stack frame, but libunwind for ARM
106         // does not support ARM vfpv3/NEON registers in DWARF format correctly.
107         // Therefore let's disable stack unwinding using DWARF information
108         // See https://github.com/dotnet/coreclr/issues/6698
109         //
110         // libunwind use following methods to unwind stack frame.
111         // UNW_ARM_METHOD_ALL          0xFF
112         // UNW_ARM_METHOD_DWARF        0x01
113         // UNW_ARM_METHOD_FRAME        0x02
114         // UNW_ARM_METHOD_EXIDX        0x04
115         putenv(const_cast<char *>("UNW_ARM_UNWIND_METHOD=6"));
116 #endif // __arm__
117
118         if (__deviceAPIDirectory.empty()) {
119                 _ERR("Empty Device API Directory");
120                 return 1;
121         } else {
122                 __deviceAPIDirectory = absolutePath(__deviceAPIDirectory);
123         }
124
125         if (__runtimeDirectory.empty()) {
126                 _ERR("Empty Runtime Directory");
127                 return 1;
128         } else {
129                 __runtimeDirectory = absolutePath(__runtimeDirectory);
130         }
131
132         // set Reference API directory
133         __refAPIDirectory = __deviceAPIDirectory + "/ref";
134
135         std::string libCoreclr(concatPath(__runtimeDirectory, "libcoreclr.so"));
136
137         _DBG("libcoreclr : %s", libCoreclr.c_str());
138
139         __coreclrLib = dlopen(libCoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
140         if (__coreclrLib == nullptr) {
141                 char *err = dlerror();
142                 _ERR("dlopen failed to open libcoreclr.so with error %s", err);
143                 return 1;
144         }
145
146 #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
147         do { \
148                 variable = (type)dlsym(__coreclrLib, name); \
149                 if (variable == nullptr) { \
150                         _ERR(name " is not found in the libcoreclr.so"); \
151                         return 1; \
152                 } \
153         } while (0)
154
155         CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, initializeClr, "coreclr_initialize");
156         CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, executeAssembly, "coreclr_execute_assembly");
157         CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, shutdown, "coreclr_shutdown");
158         CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, createDelegate, "coreclr_create_delegate");
159
160 #undef CORELIB_RETURN_IF_NOSYM
161
162         _DBG("libcoreclr dlopen and dlsym success");
163
164         if (!standalone && pluginPreload)
165                 pluginPreload();
166
167         fd = open("/proc/self", O_DIRECTORY);
168         std::string path_tmp = std::string("/proc/self/fd/") + std::to_string(fd);
169
170         std::string appRoot = path_tmp;
171         std::string appBin = concatPath(appRoot, "bin");
172         std::string appLib = concatPath(appRoot, "lib");
173         std::string probePath = appBin + ":" + appLib;
174
175         std::string tpa;
176         std::vector<std::string> searchDirectories;
177         searchDirectories.push_back(__runtimeDirectory);
178         searchDirectories.push_back(__deviceAPIDirectory);
179         searchDirectories.push_back(__refAPIDirectory);
180
181         if (pluginGetDllPath) {
182                 std::string pluginPath = pluginGetDllPath();
183                 if (!pluginPath.empty()) {
184                         searchDirectories.push_back(pluginPath);
185                 }
186         }
187
188         assembliesInDirectory(searchDirectories, tpa);
189
190         std::string nativeLibPath;
191         nativeLibPath = appLib + ":" + appBin + ":" + __nativeLibDirectory;
192
193         std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
194         if (!initializeCoreClr(appName.c_str(), probePath.c_str(), nativeLibPath.c_str(), tpa.c_str())) {
195                 _ERR("Failed to initialize coreclr");
196                 return 1;
197         }
198
199         return 0;
200 }
201
202 bool CoreRuntime::initializeCoreClr(const char* appId,
203                                                                          const char* assemblyProbePaths,
204                                                                          const char* pinvokeProbePaths,
205                                                                          const char* tpaList)
206 {
207         const char *propertyKeys[] = {
208                 "TRUSTED_PLATFORM_ASSEMBLIES",
209                 "APP_PATHS",
210                 "APP_NI_PATHS",
211                 "NATIVE_DLL_SEARCH_DIRECTORIES",
212                 "AppDomainCompatSwitch"
213         };
214
215         const char *propertyValues[] = {
216                 tpaList,
217                 assemblyProbePaths,
218                 assemblyProbePaths,
219                 pinvokeProbePaths,
220                 "UseLatestBehaviorWhenTFMNotSpecified"
221         };
222
223         std::string selfPath = readSelfPath();
224
225         int st = initializeClr(selfPath.c_str(),
226                                                         appId,
227                                                         sizeof(propertyKeys) / sizeof(propertyKeys[0]),
228                                                         propertyKeys,
229                                                         propertyValues,
230                                                         &__hostHandle,
231                                                         &__domainId);
232
233         if (st < 0) {
234                 _ERR("initialize core clr fail! (0x%08x)", st);
235                 return false;
236         }
237
238         if (pluginSetCoreclrInfo)
239                 pluginSetCoreclrInfo(__hostHandle, __domainId);
240
241         _DBG("Initialize core clr success");
242         return true;
243 }
244
245 void CoreRuntime::dispose()
246 {
247         if (__hostHandle != nullptr) {
248                 int st = shutdown(__hostHandle, __domainId);
249                 if (st < 0)
250                         _ERR("shutdown core clr fail! (0x%08x)", st);
251         }
252
253         if (dlclose(__coreclrLib) != 0)
254                 _ERR("libcoreclr.so close failed");
255
256         __coreclrLib = nullptr;
257
258         if (pluginFinalize)
259                 pluginFinalize();
260
261         if (__pluginLib != nullptr) {
262                 if (dlclose(__pluginLib) != 0)
263                         _ERR("libdotnet_plugin.so close failed");
264
265                 __pluginLib = nullptr;
266                 pluginInitialize = nullptr;
267                 pluginPreload = nullptr;
268                 pluginSetAppInfo = nullptr;
269                 pluginSetCoreclrInfo = nullptr;
270                 pluginGetDllPath = nullptr;
271                 pluginBeforeExecute = nullptr;
272                 pluginFinalize = nullptr;
273         }
274
275         _DBG("Dotnet runtime disposed");
276 }
277
278 int CoreRuntime::launch(const char* appId, const char* root, const char* path, int argc, char* argv[])
279 {
280         if (path == nullptr) {
281                 _ERR("executable path is null");
282                 return 1;
283         }
284
285         if (fileNotExist(path)) {
286                 _ERR("File not exist : %s", path);
287                 return 1;
288         }
289
290         if (pluginSetAppInfo)
291                 pluginSetAppInfo(appId, path);
292
293         int fd2 = open(root, O_DIRECTORY);
294         dup3(fd2, fd, O_CLOEXEC);
295         close(fd2);
296
297         if (pluginBeforeExecute)
298                 pluginBeforeExecute();
299
300         if (runLoggingThread() < 0) {
301                 _ERR("Failed to create logging thread");
302         }
303
304         unsigned int ret = 0;
305         int st = executeAssembly(__hostHandle, __domainId, argc, (const char**)argv, path, &ret);
306         if (st < 0)
307                 _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
308         return ret;
309 }
310
311 }  // namespace dotnetcore
312 }  // namespace runtime
313 }  // namespace tizen