Support hydra mode
[platform/core/dotnet/launcher.git] / NativeLauncher / launcher / 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 #include "launcher.h"
18 #include "log.h"
19
20 #include <launchpad.h>
21 #include <aul.h>
22
23 #include <Ecore.h>
24 #include <bundle_internal.h>
25
26 #include <map>
27 #include <vector>
28 #include <functional>
29
30 #include <unistd.h>
31 #include <dlfcn.h>
32
33
34 namespace tizen {
35 namespace runtime {
36
37 struct FdHandler {
38         Ecore_Fd_Handler *handler;
39         loader_receiver_cb receiver;
40 };
41
42 static int __argc;
43 static char **__argv;
44
45 class LaunchpadAdapterImpl : public LaunchpadAdapter
46 {
47         public:
48                 LaunchpadAdapterImpl() :
49                         callbacks(),
50                         adapter(),
51                         __isLaunched(false)
52                 { }
53                 int loaderMain(int argc, char* argv[]) override;
54
55                 std::map<int, FdHandler> handlers;
56
57         private:
58                 AppInfo appInfo;
59                 loader_lifecycle_callback_s callbacks;
60                 hydra_lifecycle_callback_s hydraCallbacks;
61                 loader_adapter_s adapter;
62                 bool __isLaunched;
63                 std::string __launchPath;
64 };
65
66 LaunchpadAdapterImpl LaunchpadImpl;
67 LaunchpadAdapter& Launchpad = LaunchpadImpl;
68
69 #define WITH_SELF(data) \
70         LaunchpadAdapterImpl* self = static_cast<LaunchpadAdapterImpl*>(data); \
71         if (self == nullptr) \
72                 _ERR("No LaunchpadImplData"); \
73         else
74
75 static Eina_Bool fdHandler(void *data, Ecore_Fd_Handler* handler)
76 {
77         WITH_SELF(data) {
78                 int fd = ecore_main_fd_handler_fd_get(handler);
79                 if (fd == -1) {
80                         _ERR("Failed to get the Ecore FD");
81                         exit(-1);
82                 }
83
84                 if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
85                         if (self->handlers.find(fd) != self->handlers.end())
86                                 self->handlers[fd].receiver(fd);
87                 } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
88                         _ERR("Ecore FD Handler Have Error");
89                         close(fd);
90                         exit(-1);
91                 }
92         }
93
94         return ECORE_CALLBACK_RENEW;
95 }
96
97 static void fdAdd(void *data, int fd, loader_receiver_cb receiver)
98 {
99         Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd,
100                         static_cast<Ecore_Fd_Handler_Flags>(ECORE_FD_READ | ECORE_FD_ERROR),
101                         fdHandler, data, nullptr, nullptr);
102         if (handler == nullptr) {
103                 _ERR("Failed to add a FD handler to ecore main loop");
104                 close(fd);
105                 exit(-1);
106         } WITH_SELF(data) {
107                 self->handlers[fd] = {handler, receiver};
108         }
109 }
110
111 static void fdRemove(void *data, int fd)
112 {
113         WITH_SELF(data) {
114                 if (self->handlers.find(fd) != self->handlers.end()) {
115                         Ecore_Fd_Handler* handler = self->handlers[fd].handler;
116                         ecore_main_fd_handler_del(handler);
117                         self->handlers.erase(fd);
118                 }
119         }
120 }
121
122 // To run dotnet-launcher on the headless device, remove build dependency from EFL.
123 #define ELEMENTARY_PATH "/usr/lib/libelementary.so.1"
124 static void* __win;
125 typedef int (*elm_init_ptr)(int argc, char **argv);
126 typedef void (*elm_config_accel_preference_set_ptr)(const char *pref);
127 typedef void* (*elm_win_add_ptr)(void* parent, const char* name, int type);
128 typedef void (*elm_win_precreated_object_set_ptr)(void* win);
129
130 static void preCreateWindow(bundle *extra, int type, void *userData)
131 {
132         struct stat sb;
133         if (stat(ELEMENTARY_PATH, &sb) != 0) {
134                 _ERR("[candidate] libelementary is not exist. skip precreation");
135                 return;
136         }
137
138         int elmInitCnt = 0;
139         void* handle = nullptr;
140         elm_init_ptr elm_init = nullptr;
141         elm_config_accel_preference_set_ptr elm_config_accel_preference_set = nullptr;
142         elm_win_add_ptr elm_win_add = nullptr;
143         elm_win_precreated_object_set_ptr elm_win_precreated_object_set = nullptr;
144
145         handle = dlopen(ELEMENTARY_PATH, RTLD_NOW | RTLD_GLOBAL);
146         if (handle) {
147                 elm_init = (elm_init_ptr)dlsym(handle, "elm_init");
148                 if (elm_init) {
149                         elmInitCnt = elm_init(__argc, __argv);
150
151                         if (!elmInitCnt) {
152                                 _ERR("[candidate] elm_init() failed");
153                                 return;
154                         }
155                 }
156
157                 elm_config_accel_preference_set = (elm_config_accel_preference_set_ptr)dlsym(handle, "elm_config_accel_preference_set");
158                 if (elm_config_accel_preference_set) {
159                         elm_config_accel_preference_set("hw");
160                 }
161
162                 elm_win_add = (elm_win_add_ptr)dlsym(handle, "elm_win_add");
163                 if (elm_win_add) {
164                         // enum value of "ELM_WIN_BASIC" is 0
165                         __win = elm_win_add(NULL, "package_name", 0);
166                         if (__win == NULL) {
167                                 _ERR("[candidate] elm_win_add() failed");
168                                 return;
169                         }
170                 }
171
172                 elm_win_precreated_object_set = (elm_win_precreated_object_set_ptr)dlsym(handle, "elm_win_precreated_object_set");
173                 if (elm_win_precreated_object_set) {
174                         elm_win_precreated_object_set(__win);
175                 }
176                 _INFO("elm window precreation is done");
177         }
178 }
179
180 int LaunchpadAdapterImpl::loaderMain(int argc, char* argv[])
181 {
182         __argc = argc;
183         __argv = argv;
184         callbacks.create = [](bundle *extra, int type, void *userData) {
185                 ecore_init();
186                 preCreateWindow(extra, type, userData);
187                 WITH_SELF(userData) {
188                         if (self->onCreate != nullptr)
189                                 self->onCreate();
190                 }
191         };
192         callbacks.launch = [](int argc, char** argv, const char* appPath,
193                                                 const char* appId, const char* pkgId,
194                                                 const char* pkgType, void* userData) -> int {
195                 WITH_SELF(userData) {
196                         const char* appRootPath = aul_get_app_root_path();
197                         if (appRootPath != nullptr) {
198                                 self->appInfo.root = std::string(appRootPath);
199                         }
200                         self->appInfo.path = appPath;
201                         self->appInfo.id = appId;
202                         self->appInfo.pkg = pkgId;
203                         self->appInfo.type = pkgType;
204                         if (self->onLaunch != nullptr)
205                                 self->onLaunch(self->appInfo, argc, argv);
206                 }
207
208                 return 0;
209         };
210         callbacks.terminate = [](int argc, char **argv, void* userData) -> int {
211                 WITH_SELF(userData) {
212                         if (self->onTerminate != nullptr)
213                                 self->onTerminate(self->appInfo, argc, argv);
214                 }
215                 return 0;
216         };
217
218         // Called before initial fork
219         hydraCallbacks.precreate = [](void* userData) {
220                 WITH_SELF(userData) {
221                         if (self->onPreCreate != nullptr)
222                                 self->onPreCreate();
223                 }
224         };
225
226         hydraCallbacks.create = [](void* userData) {
227                 ecore_init();
228         };
229
230         // Called after fork in candidate
231         hydraCallbacks.fork = [](void *userData) {
232                 ecore_fork_reset();
233         };
234
235         hydraCallbacks.terminate = [](void* userData) {
236                 ecore_shutdown();
237                 return 0;
238         };
239
240         adapter.loop_begin = [](void *data) {
241                 ecore_main_loop_begin();
242         };
243
244         adapter.loop_quit = [](void *data) {
245                 ecore_main_loop_quit();
246         };
247         adapter.add_fd = fdAdd;
248         adapter.remove_fd = fdRemove;
249
250         _INFO("launchpad_hydra_main is start");
251         int r = launchpad_hydra_main(argc, argv, &(this->hydraCallbacks),
252                 &(this->callbacks), &(this->adapter), this);
253         _INFO("launchpad_hydra_main is finished with [%d]", r);
254
255         return r;
256 }
257
258 #undef WITH_SELF
259
260 }  // namespace runtime
261 }  // namespace tizen