refactoring launcher
[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 namespace tizen {
30 namespace runtime {
31 namespace dotnetcore {
32
33 CoreRuntime::CoreRuntime() :
34   InitializeClr(nullptr),
35   ExecuteAssembly(nullptr),
36   Shutdown(nullptr),
37   CreateDelegate(nullptr),
38   coreclrLib(nullptr),
39   hostHandle(nullptr),
40   domainId(-1),
41   PreparedFunction(nullptr),
42   LaunchFunction(nullptr)
43 {
44 #define __XSTR(x) #x
45 #define __STR(x) __XSTR(x)
46
47 #ifdef DEVICE_API_DIR
48   DeviceAPIDirectory = __STR(DEVICE_API_DIR);
49 #endif
50 #ifdef RUNTIME_DIR
51   RuntimeDirectory = __STR(RUNTIME_DIR);
52 #endif
53 #ifdef NATIVE_LIB_DIR
54   NativeLibDirectory = __STR(NATIVE_LIB_DIR);
55 #endif
56
57 #ifdef USE_MANAGED_LAUNCHER
58 #ifdef CORECLR_LAUNCHER_ASSEMBLY_PATH
59   LauncherAssembly = __STR(CORECLR_LAUNCHER_ASSEMBLY_PATH);
60 #endif
61 #endif
62
63 #undef __STR
64 #undef __XSTR
65
66   _DBG("Constructor called!!");
67 }
68
69 CoreRuntime::~CoreRuntime()
70 {
71   Dispose();
72 }
73
74 int CoreRuntime::Initialize(bool standalone)
75 {
76
77   if (standalone)
78   {
79     const char *_deviceapi_directory = getenv("DeviceAPIDirectory");
80     const char *_runtime_directory = getenv("RuntimeDirectory");
81     if (_deviceapi_directory != nullptr)
82       DeviceAPIDirectory = _deviceapi_directory;
83     if (_runtime_directory != nullptr)
84       RuntimeDirectory = _runtime_directory;
85
86 #ifdef USE_MANAGED_LAUNCHER
87     const char *_launcher_assembly = getenv("LauncherAssembly");
88     if (_launcher_assembly != nullptr)
89       LauncherAssembly = _launcher_assembly;
90 #endif
91   }
92
93   if (DeviceAPIDirectory.empty())
94   {
95     _ERR("Empty Device API Directory");
96     return 1;
97   }
98   else
99   {
100     DeviceAPIDirectory = AbsolutePath(DeviceAPIDirectory);
101   }
102
103   if (RuntimeDirectory.empty())
104   {
105     _ERR("Empty Runtime Directory");
106     return 1;
107   }
108   else
109   {
110     RuntimeDirectory = AbsolutePath(RuntimeDirectory);
111   }
112
113 #ifdef USE_MANAGED_LAUNCHER
114   if (LauncherAssembly.empty())
115   {
116     _ERR("Empty Launcher Assembly");
117     return 1;
118   }
119   else
120   {
121     LauncherAssembly = AbsolutePath(LauncherAssembly);
122   }
123 #endif
124
125   std::string libcoreclr(ConcatPath(RuntimeDirectory, "libcoreclr.so"));
126
127   _DBG("libcoreclr : %s", libcoreclr.c_str());
128
129   coreclrLib = dlopen(libcoreclr.c_str(), RTLD_NOW | RTLD_LOCAL);
130   if (coreclrLib == nullptr)
131   {
132     char *err = dlerror();
133     _ERR("dlopen failed to open libcoreclr.so with error %s", err);
134     return 1;
135   }
136
137 #define CORELIB_RETURN_IF_NOSYM(type, variable, name) \
138   do { variable = (type)dlsym(coreclrLib, name); \
139     if (variable == nullptr) { \
140       _ERR(name " is not found in the libcoreclr.so"); \
141       return 1; \
142     }} while(0)
143
144   CORELIB_RETURN_IF_NOSYM(coreclr_initialize_ptr, InitializeClr, "coreclr_initialize");
145   CORELIB_RETURN_IF_NOSYM(coreclr_execute_assembly_ptr, ExecuteAssembly, "coreclr_execute_assembly");
146   CORELIB_RETURN_IF_NOSYM(coreclr_shutdown_ptr, Shutdown, "coreclr_shutdown");
147   CORELIB_RETURN_IF_NOSYM(coreclr_create_delegate_ptr, CreateDelegate, "coreclr_create_delegate");
148
149 #undef CORELIB_RETURN_IF_NOSYM
150
151   _DBG("libcoreclr dlopen and dlsym success");
152
153   _DBG("this addr : %x", this);
154   _DBG("coreclr_initialize : %x", InitializeClr);
155
156   return 0;
157 }
158
159 bool CoreRuntime::InitializeCoreClr(const char* app_id,
160                                     const char* assembly_probe_paths,
161                                     const char* pinvoke_probe_paths,
162                                     const char* tpa_list)
163 {
164   const char *propertyKeys[] =
165   {
166     "TRUSTED_PLATFORM_ASSEMBLIES",
167     "APP_PATHS",
168     "APP_NI_PATHS",
169     "NATIVE_DLL_SEARCH_DIRECTORIES",
170     "AppDomainCompatSwitch"
171   };
172
173   const char *propertyValues[] =
174   {
175     tpa_list,
176     assembly_probe_paths,
177     assembly_probe_paths,
178     pinvoke_probe_paths,
179     "UseLatestBehaviorWhenTFMNotSpecified"
180   };
181
182   std::string selfPath = ReadSelfPath();
183
184   int st = InitializeClr(
185       selfPath.c_str(),
186       app_id,
187       sizeof(propertyKeys) / sizeof(propertyKeys[0]),
188       propertyKeys,
189       propertyValues,
190       &hostHandle,
191       &domainId);
192
193   if (st < 0)
194   {
195     _ERR("initialize core clr fail! (0x%08x)", st);
196     return false;
197   }
198
199   _DBG("Initialize core clr success");
200   return true;
201 }
202
203 int CoreRuntime::RunManagedLauncher(const char* app_id, const char* app_base, const char* tpa_list)
204 {
205   if (FileNotExist(LauncherAssembly))
206   {
207     _ERR("Launcher assembly is not exist in %s", LauncherAssembly.c_str());
208     return 1;
209   }
210
211   if (!InitializeCoreClr(app_id, app_base, app_base, tpa_list))
212   {
213     _ERR("Failed to initialize coreclr");
214     return 1;
215   }
216
217 #ifdef USE_MANAGED_LAUNCHER
218   void *preparedFunctionDelegate;
219   int st = CreateDelegate(hostHandle, domainId,
220       "Tizen.Runtime.Coreclr",
221       "Tizen.Runtime.Coreclr.AssemblyManager",
222       "Prepared", &preparedFunctionDelegate);
223   if (st < 0)
224   {
225     _ERR("Create delegate for Launch prepared function is fail (0x%08x)", st);
226     return 1;
227   }
228   PreparedFunction = reinterpret_cast<PreparedFunctionPtr>(preparedFunctionDelegate);
229
230   if(PreparedFunction != nullptr)
231   {
232     PreparedFunction();
233   }
234
235   void *launchFunctionDelegate;
236   st = CreateDelegate(hostHandle, domainId,
237       "Tizen.Runtime.Coreclr",
238       "Tizen.Runtime.Coreclr.AssemblyManager",
239       "Launch", &launchFunctionDelegate);
240   if (st < 0)
241   {
242     _ERR("Create delegate for Launch managed function is fail! (0x%08x)", st);
243     return 1;
244   }
245   LaunchFunction = reinterpret_cast<LaunchFunctionPtr>(launchFunctionDelegate);
246 #endif
247   return 0;
248 }
249
250 void CoreRuntime::Dispose()
251 {
252   if (hostHandle != nullptr)
253   {
254     int st = Shutdown(hostHandle, domainId);
255     if (st < 0)
256     {
257       _ERR("shutdown core clr fail! (0x%08x)", st);
258     }
259   }
260
261   if (dlclose(coreclrLib) != 0)
262   {
263     _ERR("libcoreclr.so close failed");
264   }
265   coreclrLib = nullptr;
266
267   _DBG("Dotnet runtime disposed");
268 }
269
270 int CoreRuntime::Launch(const char* app_id, const char* root, const char* path, int argc, char* argv[])
271 {
272   if (path == nullptr)
273   {
274     _ERR("executable path is null");
275     return 1;
276   }
277
278   std::string cpppath(path);
279
280   if (IsManagedAssembly(cpppath) && !IsNativeImage(cpppath))
281   {
282     size_t extindex = cpppath.size() - 4;
283     cpppath = cpppath.substr(0, extindex) + ".ni" + cpppath.substr(extindex, 4);
284     if (!FileNotExist(cpppath))
285     {
286       path = cpppath.c_str();
287     }
288   }
289
290   if (FileNotExist(path))
291   {
292     _ERR("File not exist : %s", path);
293     return 1;
294   }
295
296   std::vector<std::string> searchDirectories = {
297     RuntimeDirectory, DeviceAPIDirectory
298 #ifdef USE_MANAGED_LAUNCHER
299     , Basename(LauncherAssembly)
300 #endif
301   };
302
303   //std::string trusted_directories = JoinStrings(searchDirectories, ":");
304   std::string tpa;
305   AssembliesInDirectory(searchDirectories, tpa);
306
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 #ifdef USE_MANAGED_LAUNCHER
313   RunManagedLauncher(app_id, probePath.c_str(), tpa.c_str());
314
315   bool success = false;
316   if (LaunchFunction != nullptr)
317   {
318     success = LaunchFunction(root, path, argc, argv);
319     if (!success)
320     {
321       _ERR("Failed to launch Application %s", path);
322     }
323     return success ? 0 : 1;
324   }
325   else
326   {
327     _ERR("Failed to find launch function");
328     return 1;
329   }
330 #else
331   int st = InitializeCoreClr(app_id, probePath.c_str(), probePath.c_str(), tpa.c_str());
332   unsigned int ret = 0;
333   st = ExecuteAssembly(hostHandle, domainId, argc, (const char**)argv, path, &ret);
334   if (st < 0)
335   {
336     _ERR("Failed to Execute Assembly %s (0x%08x)", path, st);
337   }
338   return ret;
339 #endif
340 }
341
342 }  // namespace dotnetcore
343 }  // namespace runtime
344 }  // namespace tizen