Merge branch 'tizen' into use_app_ni_path
[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                 loader_adapter_s adapter;
61                 bool __isLaunched;
62                 std::string __launchPath;
63 };
64
65 LaunchpadAdapterImpl LaunchpadImpl;
66 LaunchpadAdapter& Launchpad = LaunchpadImpl;
67
68 #define WITH_SELF(data) \
69         LaunchpadAdapterImpl* self = static_cast<LaunchpadAdapterImpl*>(data); \
70         if (self == nullptr) \
71                 _ERR("No LaunchpadImplData"); \
72         else
73
74 static Eina_Bool fdHandler(void *data, Ecore_Fd_Handler* handler)
75 {
76         WITH_SELF(data) {
77                 int fd = ecore_main_fd_handler_fd_get(handler);
78                 if (fd == -1) {
79                         _ERR("Failed to get the Ecore FD");
80                         exit(-1);
81                 }
82
83                 if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
84                         if (self->handlers.find(fd) != self->handlers.end())
85                                 self->handlers[fd].receiver(fd);
86                 } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
87                         _ERR("Ecore FD Handler Have Error");
88                         close(fd);
89                         exit(-1);
90                 }
91         }
92
93         return ECORE_CALLBACK_CANCEL;
94 }
95
96 static void fdAdd(void *data, int fd, loader_receiver_cb receiver)
97 {
98         Ecore_Fd_Handler* handler = ecore_main_fd_handler_add(fd,
99                         static_cast<Ecore_Fd_Handler_Flags>(ECORE_FD_READ | ECORE_FD_ERROR),
100                         fdHandler, data, nullptr, nullptr);
101         if (handler == nullptr) {
102                 _ERR("Failed to add a FD handler to ecore main loop");
103                 close(fd);
104                 exit(-1);
105         } WITH_SELF(data) {
106                 self->handlers[fd] = {handler, receiver};
107         }
108 }
109
110 static void fdRemove(void *data, int fd)
111 {
112         WITH_SELF(data) {
113                 if (self->handlers.find(fd) != self->handlers.end()) {
114                         Ecore_Fd_Handler* handler = self->handlers[fd].handler;
115                         ecore_main_fd_handler_del(handler);
116                         self->handlers.erase(fd);
117                 }
118         }
119 }
120
121 // To run dotnet-launcher on the headless device, remove build dependency from EFL.
122 #define ELEMENTARY_PATH "/usr/lib/libelementary.so.1"
123 static void* __win;
124 typedef int (*elm_init_ptr)(int argc, char **argv);
125 typedef void (*elm_config_accel_preference_set_ptr)(const char *pref);
126 typedef void* (*elm_win_add_ptr)(void* parent, const char* name, int type);
127 typedef void (*elm_win_precreated_object_set_ptr)(void* win);
128
129 static void preCreateWindow(bundle *extra, int type, void *userData)
130 {
131         struct stat sb;
132         if (stat(ELEMENTARY_PATH, &sb) != 0) {
133                 _ERR("[candidate] libelememantary is not exist. skip precreation");
134                 return;
135         }
136
137         int elmInitCnt = 0;
138         void* handle = nullptr;
139         elm_init_ptr elm_init = nullptr;
140         elm_config_accel_preference_set_ptr elm_config_accel_preference_set = nullptr;
141         elm_win_add_ptr elm_win_add = nullptr;
142         elm_win_precreated_object_set_ptr elm_win_precreated_object_set = nullptr;
143
144         handle = dlopen(ELEMENTARY_PATH, RTLD_NOW | RTLD_GLOBAL);
145         if (handle) {
146                 elm_init = (elm_init_ptr)dlsym(handle, "elm_init");
147                 if (elm_init) {
148                         elmInitCnt = elm_init(__argc, __argv);
149
150                         if (!elmInitCnt) {
151                                 _ERR("[candidate] elm_init() failed");
152                                 return;
153                         }
154                 }
155
156                 elm_config_accel_preference_set = (elm_config_accel_preference_set_ptr)dlsym(handle, "elm_config_accel_preference_set");
157                 if (elm_config_accel_preference_set) {
158                         elm_config_accel_preference_set("hw");
159                 }
160
161                 elm_win_add = (elm_win_add_ptr)dlsym(handle, "elm_win_add");
162                 if (elm_win_add) {
163                         // enum value of "ELM_WIN_BASIC" is 0
164                         __win = elm_win_add(NULL, "package_name", 0);
165                         if (__win == NULL) {
166                                 _ERR("[candidate] elm_win_add() failed");
167                                 return;
168                         }
169                 }
170
171                 elm_win_precreated_object_set = (elm_win_precreated_object_set_ptr)dlsym(handle, "elm_win_precreated_object_set");
172                 if (elm_win_precreated_object_set) {
173                         elm_win_precreated_object_set(__win);
174                 }
175                 _INFO("elm window precreation is done");
176         }
177 }
178
179 int LaunchpadAdapterImpl::loaderMain(int argc, char* argv[])
180 {
181         __argc = argc;
182         __argv = argv;
183         callbacks.create = [](bundle *extra, int type, void *userData) {
184                 ecore_init();
185                 preCreateWindow(extra, type, userData);
186                 WITH_SELF(userData) {
187                         if (self->onCreate != nullptr)
188                                 self->onCreate();
189                 }
190         };
191         callbacks.launch = [](int argc, char** argv, const char* appPath,
192                                                 const char* appId, const char* pkgId,
193                                                 const char* pkgType, void* userData) -> int {
194                 WITH_SELF(userData) {
195                         const char* appRootPath = aul_get_app_root_path();
196                         if (appRootPath != nullptr) {
197                                 self->appInfo.root = std::string(appRootPath);
198                         }
199                         self->appInfo.path = appPath;
200                         self->appInfo.id = appId;
201                         self->appInfo.pkg = pkgId;
202                         self->appInfo.type = pkgType;
203                         if (self->onLaunch != nullptr)
204                                 self->onLaunch(self->appInfo, argc, argv);
205                 }
206
207                 return 0;
208         };
209         callbacks.terminate = [](int argc, char **argv, void* userData) -> int {
210                 WITH_SELF(userData) {
211                         if (self->onTerminate != nullptr)
212                                 self->onTerminate(self->appInfo, argc, argv);
213                 }
214                 return 0;
215         };
216
217         adapter.loop_begin = [](void *data) {
218                 ecore_main_loop_begin();
219         };
220
221         adapter.loop_quit = [](void *data) {
222                 ecore_main_loop_quit();
223         };
224         adapter.add_fd = fdAdd;
225         adapter.remove_fd = fdRemove;
226
227         _INFO("launchpad_loader_main is start");
228         int r = launchpad_loader_main(argc, argv, &(this->callbacks), &(this->adapter), this);
229         _INFO("launchpad_loader_main is finished with [%d]", r);
230
231         return r;
232 }
233
234 #undef WITH_SELF
235
236 }  // namespace runtime
237 }  // namespace tizen