Bump up efl module version.
[platform/core/appfw/launchpad.git] / src / launchpad_loader.c
1 /*
2  * Copyright (c) 2015 - 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 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <stdbool.h>
20 #include <dlfcn.h>
21 #include <sys/prctl.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <malloc.h>
25 #include <linux/limits.h>
26 #include <Elementary.h>
27 #include <bundle_internal.h>
28 #include <vconf.h>
29
30 #include "launchpad_common.h"
31 #include "launchpad.h"
32 #include "key.h"
33
34 #define KEY_LOADER_TYPE         "loader_type"
35 #define LOADER_TYPE_COMMON      "common-loader"
36 #define LOADER_TYPE_HW          "hw-loader"
37 #define LOADER_TYPE_SW          "sw-loader"
38
39 #define PATH_LIB_VC_ELM "/usr/lib/libvc-elm.so.0"
40
41 extern bundle *launchpad_loader_get_bundle(void);
42
43 static Ecore_Fd_Handler *__fd_handler;
44 static loader_receiver_cb __receiver;
45
46 static int __argc;
47 static char **__argv;
48 static int __sys_hwacc;
49 static Evas_Object *__win;
50 static Evas_Object *__bg;
51 static Evas_Object *__conform;
52 static int __type;
53
54 enum loader_type {
55         TYPE_COMMON,
56         TYPE_SW,
57         TYPE_HW,
58         MAX_LOADER_TYPE
59 };
60
61 enum acc_type {
62         SW_ACC,
63         HW_ACC,
64         MAX_ACC_TYPE
65 };
66
67 typedef void (*loader_convertible)(void);
68
69 static void __vconf_cb(keynode_t *key, void *data)
70 {
71         const char *name;
72
73         name = vconf_keynode_get_name(key);
74         if (name && strcmp(name, VCONFKEY_SETAPPL_APP_HW_ACCELERATION) == 0) {
75                 __sys_hwacc = vconf_keynode_get_int(key);
76                 _D("sys hwacc: %d", __sys_hwacc);
77         }
78 }
79
80 static void __init_theme(void)
81 {
82         char *theme = elm_theme_list_item_path_get(eina_list_data_get(
83                         elm_theme_list_get(NULL)), NULL);
84         Eina_Bool is_exist = edje_file_group_exists(theme, "*");
85
86         if (!is_exist)
87                 _D("theme path: %s", theme);
88
89         if (theme)
90                 free(theme);
91 }
92
93 static void __init_window(void)
94 {
95         __win = elm_win_add(NULL, "package_name", ELM_WIN_BASIC);
96         if (__win == NULL) {
97                 _E("[candidate] elm_win_add() failed");
98                 return;
99         }
100
101         elm_win_precreated_object_set(__win);
102
103         __bg = elm_bg_add(__win);
104         if (__bg) {
105                 evas_object_size_hint_weight_set(__bg, EVAS_HINT_EXPAND,
106                                 EVAS_HINT_EXPAND);
107                 elm_win_resize_object_add(__win, __bg);
108                 elm_bg_precreated_object_set(__bg);
109         } else {
110                 _E("[candidate] elm_bg_add() failed");
111         }
112
113         __conform = elm_conformant_add(__win);
114         if (__conform) {
115                 evas_object_size_hint_weight_set(__conform, EVAS_HINT_EXPAND,
116                                 EVAS_HINT_EXPAND);
117                 elm_conformant_precreated_object_set(__conform);
118         } else {
119                 _E("elm_conformant_add() failed");
120         }
121 }
122
123 static void __fini_window(void)
124 {
125         _D("Drop window");
126
127         if (__conform) {
128                 evas_object_del(__conform);
129                 elm_conformant_precreated_object_set(NULL);
130                 __conform = NULL;
131         }
132
133         if (__bg) {
134                 evas_object_del(__bg);
135                 elm_bg_precreated_object_set(NULL);
136                 __bg = NULL;
137         }
138
139         if (__win) {
140                 evas_object_del(__win);
141                 elm_win_precreated_object_set(NULL);
142                 __win = NULL;
143         }
144 }
145
146 static void __preload_lib(bundle *b)
147 {
148         void *handle = NULL;
149         int i;
150         int len = 0;
151         const char **so_array;
152
153         if (!b)
154                 return;
155
156         so_array = bundle_get_str_array(b, "preload", &len);
157
158         if (!so_array)
159                 return;
160
161         for (i = 0; i < len; i++) {
162                 if (!so_array[i]) {
163                         _E("so_array[%d] is nullptr", i);
164                         continue;
165                 }
166                 if (so_array[i][0] == '\0') {
167                         _E("so_array[%d] is empty string", i);
168                         continue;
169                 }
170
171                 _D("preload %s# - handle : %p", so_array[i], handle);
172                 handle = dlopen(so_array[i], RTLD_NOW | RTLD_NODELETE);
173                 if (!handle) {
174                         _E("failed to load: %s, err: %s",
175                                 so_array[i], dlerror());
176                 }
177         }
178 }
179
180 static void __loader_create_cb(bundle *extra, int type, void *user_data)
181 {
182         int elm_init_cnt = 0;
183         int ret;
184         char *ltype = NULL;
185
186         if (extra == NULL) {
187                 _E("No extra data");
188                 return;
189         }
190
191         bundle_get_str(extra, KEY_LOADER_TYPE, &ltype);
192
193         if (ltype == NULL) {
194                 _E("No loader type");
195                 return;
196         }
197
198 #ifdef TIZEN_FEATURE_LOADER_PRIORITY
199         launchpad_loader_set_priority(19);
200 #endif
201
202         if (!strcmp(LOADER_TYPE_COMMON, ltype))
203                 __type = TYPE_COMMON;
204         else if (!strcmp(LOADER_TYPE_SW, ltype))
205                 __type = TYPE_SW;
206         else if (!strcmp(LOADER_TYPE_HW, ltype))
207                 __type = TYPE_HW;
208
209         _D("Loader type:%d", __type);
210
211         __preload_lib(extra);
212
213         elm_init_cnt = elm_init(__argc, __argv);
214         _D("[candidate] elm init, returned: %d", elm_init_cnt);
215         setenv("AUL_LOADER_INIT", "1", 1);
216
217         switch (__type) {
218         case TYPE_SW:
219                 elm_config_accel_preference_set("none");
220                 __init_window();
221                 break;
222
223         case TYPE_HW:
224                 elm_config_accel_preference_set("hw");
225                 __init_window();
226                 break;
227
228         default:
229                 __init_theme();
230                 break;
231         }
232
233         ret = vconf_get_int(VCONFKEY_SETAPPL_APP_HW_ACCELERATION, &__sys_hwacc);
234         if (ret != VCONF_OK) {
235                 _E("Failed to get vconf int: %s",
236                                 VCONFKEY_SETAPPL_APP_HW_ACCELERATION);
237         }
238
239         ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
240                         __vconf_cb, NULL);
241         if (ret != 0) {
242                 _E("Failed to register callback for %s",
243                                 VCONFKEY_SETAPPL_APP_HW_ACCELERATION);
244         }
245 #ifdef TIZEN_FEATURE_LOADER_PRIORITY
246         launchpad_loader_set_priority(0);
247 #endif
248 }
249
250 static loader_convertible __converter_table[MAX_LOADER_TYPE][MAX_ACC_TYPE] = {
251         [TYPE_COMMON][SW_ACC] = NULL,
252         [TYPE_COMMON][HW_ACC] = NULL,
253         [TYPE_SW][SW_ACC] = NULL,
254         [TYPE_SW][HW_ACC] = __fini_window,
255         [TYPE_HW][SW_ACC] = __fini_window,
256         [TYPE_HW][HW_ACC] = NULL,
257 };
258
259 static int __loader_launch_cb(int argc, char **argv, const char *app_path,
260                 const char *appid, const char *pkgid, const char *pkg_type,
261                 void *user_data)
262 {
263         const char *hwacc;
264         bundle *kb = launchpad_loader_get_bundle();
265         int acc = SW_ACC;
266         loader_convertible convert;
267 #ifdef TIZEN_FEATURE_PRIORITY_CHANGE
268         const char *high_priority;
269 #endif
270
271         vconf_ignore_key_changed(VCONFKEY_SETAPPL_APP_HW_ACCELERATION,
272                         __vconf_cb);
273         if (kb == NULL)
274                 return 0;
275
276 #ifdef TIZEN_FEATURE_PRIORITY_CHANGE
277         high_priority = bundle_get_val(kb, AUL_K_HIGHPRIORITY);
278         if (high_priority) {
279                 if (!strcmp(high_priority, "true"))
280                         launchpad_loader_set_priority(-12);
281                 bundle_del(kb, AUL_K_HIGHPRIORITY);
282         }
283 #endif
284
285         hwacc = bundle_get_val(kb, AUL_K_HWACC);
286
287         if (!hwacc)
288                 return 0;
289
290         if (strcmp(hwacc, "USE") == 0 ||
291                 (strcmp(hwacc, "SYS") == 0 &&
292                         __sys_hwacc == SETTING_HW_ACCELERATION_ON)) {
293                 acc = HW_ACC;
294         }
295
296         convert = __converter_table[__type][acc];
297         if (convert)
298                 convert();
299
300         return 0;
301 }
302
303 static int __loader_terminate_cb(int argc, char **argv, void *user_data)
304 {
305         void *handle;
306         int (*dl_main)(int, char **);
307         char err_str[MAX_LOCAL_BUFSZ];
308         char old_cwd[PATH_MAX];
309         bool restore = false;
310         char *libdir = NULL;
311
312         SECURE_LOGD("[candidate] Launch real application (%s)",
313                         argv[LOADER_ARG_PATH]);
314
315         if (getcwd(old_cwd, sizeof(old_cwd)) == NULL)
316                 goto do_dlopen;
317
318         libdir = _get_libdir(argv[LOADER_ARG_PATH]);
319         if (libdir == NULL)
320                 goto do_dlopen;
321
322         /* To support 2.x applications which use their own shared libraries.
323          * We set '-rpath' to make the dynamic linker looks in the CWD forcely,
324          * so here we change working directory to find shared libraries well.
325          */
326         if (chdir(libdir))
327                 _E("failed to chdir: %d", errno);
328         else
329                 restore = true;
330
331 do_dlopen:
332         handle = dlopen(argv[LOADER_ARG_PATH],
333                         RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
334         if (handle == NULL) {
335                 _E("dlopen failed(%s). Please complile with -fPIE and " \
336                                 "link with -pie flag", dlerror());
337                 goto do_exec;
338         }
339
340         dlerror();
341
342         if (restore && chdir(old_cwd))
343                 _E("failed to chdir: %d", errno);
344
345         dl_main = dlsym(handle, "main");
346         if (dl_main == NULL) {
347                 _E("dlsym not founded(%s). Please export 'main' function",
348                                 dlerror());
349                 dlclose(handle);
350                 goto do_exec;
351         }
352
353         free(libdir);
354         return dl_main(argc, argv);
355
356 do_exec:
357         if (access(argv[LOADER_ARG_PATH], F_OK | R_OK)) {
358                 SECURE_LOGE("access() failed for file: \"%s\", error: %d (%s)",
359                                 argv[LOADER_ARG_PATH], errno,
360                                 strerror_r(errno, err_str, sizeof(err_str)));
361         } else {
362                 SECURE_LOGD("[candidate] Exec application (%s)",
363                                 __argv[LOADER_ARG_PATH]);
364                 _close_all_fds();
365                 if (libdir)
366                         setenv("LD_LIBRARY_PATH", libdir, 1);
367                 free(libdir);
368                 unsetenv("AUL_LOADER_INIT");
369                 unsetenv("VC_ELM_INIT");
370                 if (execv(argv[LOADER_ARG_PATH], argv) < 0) {
371                         _send_message_to_logger(argv[LOADER_ARG_PATH],
372                                 "Failed to execute a file. error(%d:%s)",
373                                 errno,
374                                 strerror_r(errno, err_str, sizeof(err_str)));
375                 }
376         }
377
378         return -1;
379 }
380
381 static Eina_Bool __process_fd_handler(void *data, Ecore_Fd_Handler *handler)
382 {
383         int fd;
384
385         fd = ecore_main_fd_handler_fd_get(handler);
386         if (fd == -1) {
387                 _D("[candidate] ECORE_FD_GET");
388                 exit(-1);
389         }
390
391         if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ)) {
392                 if (__receiver)
393                         __receiver(fd);
394         } else if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR)) {
395                 _D("[candidate] ECORE_FD_ERROR");
396                 close(fd);
397                 exit(-1);
398         }
399
400         return ECORE_CALLBACK_CANCEL;
401 }
402
403 static void __adapter_loop_begin(void *user_data)
404 {
405         ecore_main_loop_begin();
406 }
407
408 static void __adapter_loop_quit(void *user_data)
409 {
410         ecore_main_loop_quit();
411 }
412
413 static void __adapter_add_fd(void *user_data, int fd,
414                 loader_receiver_cb receiver)
415 {
416         __fd_handler = ecore_main_fd_handler_add(fd,
417                         ECORE_FD_READ | ECORE_FD_ERROR, __process_fd_handler,
418                         NULL, NULL, NULL);
419         if (__fd_handler == NULL) {
420                 _D("fd_handler is NULL");
421                 close(fd);
422                 exit(-1);
423         }
424
425         __receiver = receiver;
426 }
427
428 static void __adapter_remove_fd(void *user_data, int fd)
429 {
430         if (__fd_handler) {
431                 ecore_main_fd_handler_del(__fd_handler);
432                 __fd_handler = NULL;
433                 __receiver = NULL;
434         }
435 }
436
437 int main(int argc, char **argv)
438 {
439         loader_lifecycle_callback_s callbacks = {
440                 .create = __loader_create_cb,
441                 .launch = __loader_launch_cb,
442                 .terminate = __loader_terminate_cb
443         };
444
445         loader_adapter_s adapter = {
446                 .loop_begin = __adapter_loop_begin,
447                 .loop_quit = __adapter_loop_quit,
448                 .add_fd = __adapter_add_fd,
449                 .remove_fd = __adapter_remove_fd
450         };
451
452         __argc = argc;
453         __argv = argv;
454
455         return launchpad_loader_main(argc, argv, &callbacks, &adapter, NULL);
456 }
457