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