e1079befc5cd9f8f7452463ce87b03a80523fa49
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / exec / loader.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 #include "core_runtime.h"
18 #include "utils.h"
19 #include "log.h"
20
21 #include <cstdio>
22 #include <vector>
23 #include <memory>
24
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <sys/prctl.h>
28
29 #include <glib.h>
30 #include <glib-unix.h>
31
32 #include <launchpad.h>
33 #include <aul.h>
34
35 using tizen::runtime::dotnetcore::CoreRuntime;
36
37 static const char* KEY_APP_TYPE = "--appType";
38 static const char* KEY_TIZEN_UIFW = "TIZEN_UIFW";
39 static const char* KEY_PROFILE = "--profile";
40
41 static guint __fd_handler;
42 static loader_receiver_cb __receiver;
43
44 // To precreate window(EFL/DALI), argc and argv should be passed.
45 // But, create callback of loader doesnot pass that to parameter.
46 // So, store argc and argv and use that to precreation.
47 // If window precreation code moves to managed, removed below code.
48 static int __argc;
49 static char **__argv;
50
51 typedef struct AppInfo {
52         std::string root;
53         std::string app_path;
54         std::string appid;
55         std::string pkgid;
56 } AppInfo;
57 static AppInfo __appInfo;
58
59 // Collect/use multicorejit profile or not
60 static bool profile;
61
62 namespace {
63 GMainLoop* __loop = nullptr;
64 }  // namespace
65
66 //################## Code for running event loop for loader ####################
67
68 static gboolean __process_fd_handler(int fd, GIOCondition condition, gpointer user_data)
69 {
70         if (condition & G_IO_IN) {
71                 if (__receiver) {
72                         __receiver(fd);
73                 }
74         } else if (condition & (G_IO_HUP | G_IO_ERR)) {
75                 _ERR("[candidate] error condition: %d", static_cast<int>(condition));
76                 close(fd);
77                 exit(-1);
78         }
79
80   return G_SOURCE_REMOVE;
81 }
82
83 static void __adapter_loop_begin(void *user_data)
84 {
85         __loop = g_main_loop_new(nullptr, FALSE);
86         g_main_loop_run(__loop);
87 }
88
89 static void __adapter_loop_quit(void *user_data)
90 {
91         if (__loop != nullptr) {
92                 g_main_loop_quit(__loop);
93                 g_main_loop_unref(__loop);
94                 __loop = nullptr;
95         }
96 }
97
98 static void __adapter_add_fd(void *user_data, int fd, loader_receiver_cb receiver)
99 {
100         __fd_handler = g_unix_fd_add(fd,
101         static_cast<GIOCondition>(G_IO_IN | G_IO_HUP | G_IO_ERR), __process_fd_handler, nullptr);
102         if (__fd_handler == 0) {
103                 _ERR("fd_handler is NULL");
104                 close(fd);
105                 exit(-1);
106         }
107
108         __receiver = receiver;
109 }
110
111 static void __adapter_remove_fd(void *user_data, int fd)
112 {
113         if (__fd_handler != 0) {
114                 g_source_remove(__fd_handler);
115                 __fd_handler = 0;
116                 __receiver = NULL;
117         }
118 }
119
120 //################## Code for managing loader life-cycle #######################
121
122 static void __loader_create_cb(bundle *extra, int type, void *user_data)
123 {
124         char *appType = NULL;
125         if (bundle_get_str(extra, KEY_APP_TYPE, &appType) != BUNDLE_ERROR_NONE) {
126                 appType = NULL;
127         }
128
129         char *uifw = NULL;
130         bundle_get_str(extra, KEY_TIZEN_UIFW, &uifw);
131         if (uifw != NULL) {
132                 setenv(KEY_TIZEN_UIFW, uifw, 1);
133                 _INFO("TIZEN_UIFW is set to %s", uifw);
134         }
135
136         char *profile_str = NULL;
137         profile = false;
138         bundle_get_str(extra, KEY_PROFILE, &profile_str);
139         if (profile_str != NULL) {
140                 if (!strcmp(profile_str, "true")) {
141                         profile = true;
142                 } else if (!strcmp(profile_str, "false")) {
143                         profile = false;
144                 } else {
145                         _DBG("PROFILE value %s not recognized. Valid values: true, false. Turn off PROFILE mode as default", profile_str);
146             }
147         }
148
149         char *ui_thread = nullptr;
150         bundle_get_str(extra, "TIZEN_UI_THREAD", &ui_thread);
151         if (ui_thread != nullptr && !strcmp(ui_thread, "true")) {
152                 setenv("TIZEN_UI_THREAD", "true", 1);
153                 _INFO("TIZEN_UI_THREAD is set");
154         }
155
156         // initialize CoreRuntime (launchmode, dlog redirection enable, root path NULL)
157         if (CoreRuntime::initialize(appType ? appType : "dotnet", LaunchMode::loader) != 0) {
158                 _ERR("Failed to initialized");
159         } else {
160                 _INFO("Success to initialized");
161         }
162 }
163
164 static int __loader_prelaunch_cb(int argc, char **argv, const char *app_path,
165                 const char *appid, const char *pkgid, const char *pkg_type,
166                 void *user_data)
167 {
168         int ret = launchpad_loader_block_threads();
169         if (ret != 0) {
170                 _ERR("Failed to prelaunch");
171         }
172         return ret;
173 }
174
175 static int __loader_launch_cb(int argc, char **argv, const char *app_path,
176                 const char *appid, const char *pkgid, const char *pkg_type,
177                 void *user_data)
178 {
179         const char* root_path = aul_get_app_root_path();
180         if (root_path != NULL) {
181                 __appInfo.root = root_path;
182         }
183         __appInfo.app_path = app_path;
184         __appInfo.appid = appid;
185         __appInfo.pkgid = pkgid;
186
187         return launchpad_loader_unblock_threads();
188 }
189
190 static int __loader_terminate_cb(int argc, char **argv, void *user_data)
191 {
192         _INFO("launch request with app path : %s", __appInfo.app_path.c_str());
193
194         // The launchpad pass the name of exe file to the first argument.
195         // For the C# spec, we have to skip this first argument.
196         if (CoreRuntime::launch(__appInfo.appid.c_str(), __appInfo.root.c_str(),
197                                                 __appInfo.app_path.c_str(), argc - 1, argv + 1, profile)) {
198                 _ERR("Failed to launch");
199                 return -1;
200         }
201
202         return 0;
203 }
204
205 //################## Main Code #################################################
206
207 extern "C" int realMain(int argc, char *argv[])
208 {
209         _INFO("##### Run in candidate mode #####");
210
211         // change cmdline from dotnet-hydra-loader to dotnet-loader
212         if (strcmp(argv[0], "/usr/bin/dotnet-hydra-loader") == 0) {
213                 memset(argv[0], '\0', strlen("/usr/bin/dotnet-hydra-loader"));
214                 snprintf(argv[0], strlen("/usr/bin/dotnet-loader") + 1,
215                                                 "/usr/bin/dotnet-loader");
216         }
217
218         loader_lifecycle_callback_s callbacks = {
219                 .create = __loader_create_cb,
220                 .prelaunch = __loader_prelaunch_cb,
221                 .launch = __loader_launch_cb,
222                 .terminate = __loader_terminate_cb
223         };
224
225         loader_adapter_s adapter = {
226                 .loop_begin = __adapter_loop_begin,
227                 .loop_quit = __adapter_loop_quit,
228                 .add_fd = __adapter_add_fd,
229                 .remove_fd = __adapter_remove_fd
230         };
231
232         int ret = launchpad_loader_main(argc, argv, &callbacks, &adapter, NULL);
233
234         CoreRuntime::finalize();
235
236         return ret;
237 }
238
239 int main(int argc, char *argv[])
240 {
241         __argc = argc;
242         __argv = argv;
243
244         return realMain(argc, argv);
245 }