Initialize Tizen 2.3
[framework/appfw/aul-1.git] / process_pool / launchpad.c
1 /*
2  * Copyright (c) 2014 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 <stdio.h>
18 #include <string.h>
19 #include <dlfcn.h>
20 #include <X11/Xlib.h>
21 #include <sys/types.h>
22 #include <signal.h>
23 #include <dirent.h>
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <sys/wait.h>
27 #include <poll.h>
28 #include <sys/prctl.h>
29 #include <malloc.h>
30
31 #include "app_sock.h"
32 #include "aul.h"
33
34 #include "config.h"
35
36 #include "menu_db_util.h"
37 #include "simple_util.h"
38 #include "access_control.h"
39 #include "preload.h"
40 #include "preexec.h"
41 #include "perf.h"
42 #include "sigchild.h"
43 #include "aul_util.h"
44
45 #include "heap_dbg.h"
46
47 #include "util_x.h"
48
49 #include "gl.h"
50
51 #include <sys/time.h>
52 #include <sys/resource.h>
53 #include <sqlite3.h>
54
55 #include "process_pool.h"
56 #include <Elementary.h>
57 #include <Ecore.h>
58
59 #define _static_ static inline
60 #define SQLITE_FLUSH_MAX        (1048576)       /* (1024*1024) */
61 #define AUL_POLL_CNT            15
62 #define AUL_PR_NAME                     16
63
64 #define EXEC_DUMMY_EXPIRED 5
65 #define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a))
66 #define LOWEST_PRIO 20
67 #define DUMMY_NONE 0
68
69 static char *launchpad_cmdline;
70 static char *__appid = NULL;
71 static int initialized = 0;
72 static int candidate_pid = DUMMY_NONE;
73 static int candidate_fd  = -1;
74 static int last_dummy_exec_time = 0;
75 const char* const HOME = "HOME";
76 const char* const APP_HOME_PATH = "/opt/home/app";
77 const char* const ROOT_HOME_PATH = "/opt/home/root";
78
79 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb);
80 _static_ int __prepare_exec(const char *pkg_name,
81                                 const char *app_path, app_info_from_db * menu_info,
82                                 bundle * kb);
83 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
84 _static_ char **__create_argc_argv(bundle * kb, int *margc);
85 _static_ int __normal_fork_exec(int argc, char **argv);
86 _static_ void __real_launch(const char *app_path, bundle * kb);
87 _static_ int __candidate_process_real_launch(int dummy_client_fd, app_pkt_t* pkt);
88 static inline int __parser(const char *arg, char *out, int out_size);
89 _static_ void __modify_bundle(bundle * kb, int caller_pid,
90                                 app_info_from_db * menu_info, int cmd);
91 _static_ int __child_raise_win_by_x(int pid, void *priv);
92 _static_ int __raise_win_by_x(int pid);
93 _static_ int __send_to_sigkill(int pid);
94 _static_ int __term_app(int pid);
95 _static_ int __resume_app(int pid);
96 _static_ int __real_send(int clifd, int ret);
97 _static_ void __send_result_to_caller(int clifd, int ret);
98 _static_ void __prepare_candidate_process(int main_fd, int pool_fd, int client_fd);
99 _static_ void __launchpad_main_loop(int main_fd, int pool_fd);
100 _static_ int __launchpad_pre_init(int argc, char **argv);
101 _static_ int __launchpad_post_init();
102
103 extern ail_error_e ail_db_close(void);
104
105
106 static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
107                                                         const char *pkgname, bundle *kb);
108
109
110 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
111 {
112         const char *str;
113
114         setenv("PKG_NAME", _get_pkgname(menu_info), 1);
115
116         USE_ENGINE("gl")
117
118         str = bundle_get_val(kb, AUL_K_STARTTIME);
119         if (str != NULL)
120                 setenv("APP_START_TIME", str, 1);
121
122         if (menu_info->hwacc != NULL)
123                 setenv("HWACC", menu_info->hwacc, 1);
124         if (menu_info->taskmanage != NULL)
125                 setenv("TASKMANAGE", menu_info->taskmanage, 1);
126 }
127
128 _static_ int __prepare_exec(const char *pkg_name,
129                                 const char *app_path, app_info_from_db * menu_info,
130                                 bundle * kb)
131 {
132         char *file_name;
133         char process_name[AUL_PR_NAME];
134         int ret;
135
136         /* Set new session ID & new process group ID*/
137         /* In linux, child can set new session ID without check permission */
138         /* TODO : should be add to check permission in the kernel*/
139         setsid();
140
141         __preexec_run(menu_info->pkg_type, pkg_name, app_path);
142
143         /* SET PRIVILEGES*/
144         SECURE_LOGD("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path);
145         if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) {
146                  _D("fail to set privileges - check your package's credential : %d\n", ret);
147                 return -1;
148         }
149         /* SET DUMPABLE - for coredump*/
150         prctl(PR_SET_DUMPABLE, 1);
151
152         /* SET PROCESS NAME*/
153         if (app_path == NULL) {
154                 _D("app_path should not be NULL - check menu db");
155                 return -1;
156         }
157         file_name = strrchr(app_path, '/') + 1;
158         if (file_name == NULL) {
159                 _D("can't locate file name to execute");
160                 return -1;
161         }
162         memset(process_name, '\0', AUL_PR_NAME);
163         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
164         prctl(PR_SET_NAME, process_name);
165
166         /* SET ENVIROMENT*/
167         __set_env(menu_info, kb);
168
169         return 0;
170 }
171
172 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
173 {
174         int datalen;
175         int ret;
176         bundle_raw *kb_data;
177
178         bundle_encode(kb, &kb_data, &datalen);
179         if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
180                 _E("error request fake launch - error code = %d", ret);
181         free(kb_data);
182         return ret;
183 }
184
185 _static_ char **__create_argc_argv(bundle * kb, int *margc)
186 {
187         char **argv;
188         int argc;
189
190         argc = bundle_export_to_argv(kb, &argv);
191
192         *margc = argc;
193         return argv;
194 }
195
196 _static_ int __normal_fork_exec(int argc, char **argv)
197 {
198         _D("start real fork and exec\n");
199
200         if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
201                 if (errno == EACCES)
202                         _E("such a file is no executable - %s", argv[0]);
203                 else
204                         _E("unknown executable error - %s", argv[0]);
205                 return -1;
206         }
207         /* never reach*/
208         return 0;
209 }
210
211 _static_ void __real_launch(const char *app_path, bundle * kb)
212 {
213         int app_argc;
214         char **app_argv;
215         int i;
216
217         app_argv = __create_argc_argv(kb, &app_argc);
218         app_argv[0] = strdup(app_path);
219
220         for (i = 0; i < app_argc; i++) {
221                 if( (i%2) == 1)
222                         continue;
223                 SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
224         }
225
226         PERF("setup argument done");
227
228         /* Temporary log: launch time checking */
229         LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
230
231         __preload_exec(app_argc, app_argv);
232
233         __normal_fork_exec(app_argc, app_argv);
234 }
235
236 _static_ int __candidate_process_real_launch(int dummy_client_fd, app_pkt_t* pkt)
237 {
238         return __send_pkt_raw_data(dummy_client_fd, pkt);
239 }
240
241 /*
242  * Parsing original app path to retrieve default bundle
243  *
244  * -1 : Invalid sequence
245  * -2 : Buffer overflow
246  *
247  */
248 static inline int __parser(const char *arg, char *out, int out_size)
249 {
250         register int i;
251         int state = 1;
252         char *start_out = out;
253
254         if (arg == NULL || out == NULL) {
255                 /* Handles null buffer*/
256                 return 0;
257         }
258
259         for (i = 0; out_size > 1; i++) {
260                 switch (state) {
261                 case 1:
262                         switch (arg[i]) {
263                         case ' ':
264                         case '\t':
265                                 state = 5;
266                                 break;
267                         case '\0':
268                                 state = 7;
269                                 break;
270                         case '\"':
271                                 state = 2;
272                                 break;
273                         case '\\':
274                                 state = 4;
275                                 break;
276                         default:
277                                 *out = arg[i];
278                                 out++;
279                                 out_size--;
280                                 break;
281                         }
282                         break;
283                 case 2: /* escape start*/
284                         switch (arg[i]) {
285                         case '\0':
286                                 state = 6;
287                                 break;
288                         case '\"':
289                                 state = 1;
290                                 break;
291                         default:
292                                 *out = arg[i];
293                                 out++;
294                                 out_size--;
295                                 break;
296                         }
297                         break;
298                 case 4: /* character escape*/
299                         if (arg[i] == '\0') {
300                                 state = 6;
301                         } else {
302                                 *out = arg[i];
303                                 out++;
304                                 out_size--;
305                                 state = 1;
306                         }
307                         break;
308                 case 5: /* token*/
309                         if (out != start_out) {
310                                 *out = '\0';
311                                 out_size--;
312                                 return i;
313                         }
314                         i--;
315                         state = 1;
316                         break;
317                 case 6:
318                         return -1;      /* error*/
319                 case 7: /* terminate*/
320                         *out = '\0';
321                         out_size--;
322                         return 0;
323                 default:
324                         state = 6;
325                         break;  /* error*/
326                 }
327         }
328
329         if (out_size == 1) {
330                 *out = '\0';
331         }
332         /* Buffer overflow*/
333         return -2;
334 }
335
336 _static_ void __modify_bundle(bundle * kb, int caller_pid,
337                                 app_info_from_db * menu_info, int cmd)
338 {
339         bundle_del(kb, AUL_K_PKG_NAME);
340         bundle_del(kb, AUL_K_EXEC);
341         bundle_del(kb, AUL_K_PACKAGETYPE);
342         bundle_del(kb, AUL_K_HWACC);
343         bundle_del(kb, AUL_K_TASKMANAGE);
344
345         /* Parse app_path to retrieve default bundle*/
346         if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_START_ASYNC || cmd == APP_OPEN || cmd == APP_RESUME) {
347                 char *ptr;
348                 char exe[MAX_PATH_LEN];
349                 int flag;
350
351                 ptr = _get_original_app_path(menu_info);
352
353                 flag = __parser(ptr, exe, sizeof(exe));
354                 if (flag > 0) {
355                         char key[256];
356                         char value[256];
357
358                         ptr += flag;
359                         SECURE_LOGD("parsing app_path: EXEC - %s\n", exe);
360
361                         do {
362                                 flag = __parser(ptr, key, sizeof(key));
363                                 if (flag <= 0)
364                                         break;
365                                 ptr += flag;
366
367                                 flag = __parser(ptr, value, sizeof(value));
368                                 if (flag < 0)
369                                         break;
370                                 ptr += flag;
371
372                                 /*bundle_del(kb, key);*/
373                                 bundle_add(kb, key, value);
374                         } while (flag > 0);
375                 } else if (flag == 0) {
376                         _D("parsing app_path: No arguments\n");
377                 } else {
378                         _D("parsing app_path: Invalid argument\n");
379                 }
380         }
381 }
382
383 _static_ int __child_raise_win_by_x(int pid, void *priv)
384 {
385         return x_util_raise_win(pid);
386 }
387
388 _static_ int __raise_win_by_x(int pid)
389 {
390         int pgid;
391         if (x_util_raise_win(pid) == 0)
392                 return 0;
393
394         /* support app launched by shell script*/
395         pgid = getpgid(pid);
396         _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
397            pgid, pid);
398
399         if (pgid <= 1)
400                 return -1;
401         if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0)
402                 return -1;
403
404         return 0;
405 }
406
407 _static_ int __send_to_sigkill(int pid)
408 {
409         int pgid;
410
411         pgid = getpgid(pid);
412         if (pgid <= 1)
413                 return -1;
414
415         if (killpg(pgid, SIGKILL) < 0)
416                 return -1;
417
418         return 0;
419 }
420
421 _static_ int __term_app(int pid)
422 {
423         int dummy;
424         if (__app_send_raw
425                 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
426                 _D("terminate packet send error - use SIGKILL");
427                 if (__send_to_sigkill(pid) < 0) {
428                         _E("fail to killing - %d\n", pid);
429                         return -1;
430                 }
431         }
432         _D("term done\n");
433         return 0;
434 }
435
436 _static_ int __resume_app(int pid)
437 {
438         int dummy;
439         int ret;
440         if ((ret =
441                  __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
442                                 sizeof(int))) < 0) {
443                 if (ret == -EAGAIN)
444                         _E("resume packet timeout error");
445                 else {
446                         _D("resume packet send error - use raise win");
447                         if (__raise_win_by_x(pid) < 0) {
448                                 _E("raise failed - %d resume fail\n", pid);
449                                 _E("we will term the app - %d\n", pid);
450                                 __send_to_sigkill(pid);
451                                 ret = -1;
452                         } else
453                                 ret = 0;
454                 }
455         }
456         _D("resume done\n");
457         return ret;
458 }
459
460 static int __get_caller_pid(bundle *kb)
461 {
462         const char *pid_str;
463         int pid;
464
465         pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
466         if(pid_str)
467                 goto end;
468
469         pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
470         if (pid_str == NULL)
471                 return -1;
472
473 end:
474         pid = atoi(pid_str);
475         if (pid <= 1)
476                 return -1;
477
478         return pid;
479 }
480
481 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
482 {
483         int pid;
484         char tmp_pid[MAX_PID_STR_BUFSZ];
485         int datalen;
486         bundle_raw *kb_data;
487         int res;
488
489         if ((pid = __get_caller_pid(kb)) < 0)
490                         return AUL_R_ERROR;
491
492         snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
493
494         bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
495
496         bundle_encode(kb, &kb_data, &datalen);
497         if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0)
498                 res = AUL_R_ERROR;
499
500         free(kb_data);
501
502         return res;
503 }
504
505 _static_ int __real_send(int clifd, int ret)
506 {
507         if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
508                 if (errno == EPIPE) {
509                         _E("send failed due to EPIPE.\n");
510                         close(clifd);
511                         return -1;
512                 }
513                 _E("send fail to client");
514         }
515
516         close(clifd);
517         return 0;
518 }
519
520 _static_ void __send_result_to_caller(int clifd, int ret)
521 {
522         char *cmdline;
523         int wait_count;
524         int cmdline_changed = 0;
525         int cmdline_exist = 0;
526         int r;
527
528         if (clifd == -1)
529                 return;
530
531         if (ret <= 1) {
532                 __real_send(clifd, ret);
533                 return;
534         }
535         /* check normally was launched?*/
536         wait_count = 1;
537         do {
538                 cmdline = __proc_get_cmdline_bypid(ret);
539                 if (cmdline == NULL) {
540                         _E("error founded when being launched with %d", ret);
541
542                 } else if (strcmp(cmdline, launchpad_cmdline)) {
543                         free(cmdline);
544                         cmdline_changed = 1;
545                         break;
546                 } else {
547                         cmdline_exist = 1;
548                         free(cmdline);
549                 }
550
551                 _D("-- now wait to change cmdline --");
552                 usleep(50 * 1000);      /* 50ms sleep*/
553                 wait_count++;
554         } while (wait_count <= 20);     /* max 50*20ms will be sleep*/
555
556         if ((!cmdline_exist) && (!cmdline_changed)) {
557                 __real_send(clifd, -1); /* abnormally launched*/
558                 return;
559         }
560
561         if (!cmdline_changed)
562                 _E("process launched, but cmdline not changed");
563
564         if(__real_send(clifd, ret) < 0) {
565                 r = kill(ret, SIGKILL);
566                 if (r == -1)
567                         _E("send SIGKILL: %s", strerror(errno));
568         }
569
570         return;
571 }
572
573 _static_ int __candidate_process_prepare_exec(const char *pkg_name,
574                                                         const char *app_path, app_info_from_db *menu_info,
575                                                         bundle *kb)
576 {
577         const char *file_name = NULL;
578         char process_name[AUL_PR_NAME] = { 0, };
579         int ret = 0;
580
581         /* SET PRIVILEGES*/
582         SECURE_LOGD("[candidata] pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path);
583         if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) {
584                 _D("fail to set privileges - check your package's credential : %d\n", ret);
585                 return -1;
586         }
587
588         //XXX: Check CAP_MAC_ADMIN
589 #if 0
590         /* SET INHERIT BIT FOR CAP_MAC_ADMIN TO WHOLE THREAD */
591         EXECUTE_ON_WHOLE_THREAD(__set_inherit_bit_for_CAP_MAC_ADMIN, SIGUSR1);
592 #endif
593
594         /* SET PROCESS NAME*/
595         if (app_path == NULL) {
596                 _D("app_path should not be NULL - check menu db");
597                 return -1;
598         }
599
600         file_name = strrchr(app_path, '/') + 1;
601         if (file_name == NULL) {
602                 _D("can't locate file name to execute");
603                 return -1;
604         }
605         memset(process_name, '\0', AUL_PR_NAME);
606         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
607         prctl(PR_SET_NAME, process_name);
608
609         /* SET ENVIROMENT*/
610         __set_env(menu_info, kb);
611
612         return 0;
613 }
614
615 static bundle *_s_bundle = NULL;
616 static void __at_exit_to_release_bundle()
617 {
618         if (_s_bundle) {
619                 bundle_free(_s_bundle);
620                 _s_bundle = NULL;
621         }
622 }
623
624 static void __release_appid_at_exit(void)
625 {
626         if (__appid != NULL) {
627                 free(__appid);
628         }
629 }
630
631 _static_ void __candidate_process_launchpad_main_loop(app_pkt_t* pkt, char* out_app_path, int* out_argc, char ***out_argv)
632 {
633         bundle *kb = NULL;
634         app_info_from_db *menu_info = NULL;
635
636         const char *pkg_name = NULL;
637         const char *app_path = NULL;
638
639         kb = bundle_decode(pkt->data, pkt->len);
640         if (!kb) {
641                 _E("bundle decode error");
642                 exit(-1);
643         }
644
645         if (_s_bundle != NULL) {
646                 bundle_free(_s_bundle);
647         }
648         _s_bundle = kb;
649         atexit(__at_exit_to_release_bundle);
650
651         pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
652         SECURE_LOGD("pkg name : %s", pkg_name);
653
654         menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
655         if (menu_info == NULL) {
656                 _D("such pkg no found");
657                 exit(-1);
658         }
659
660         app_path = _get_app_path(menu_info);
661         if (app_path == NULL) {
662                 _E("app_path is NULL");
663                 exit(-1);
664         }
665
666         if (app_path[0] != '/') {
667                 _E("app_path is not absolute path");
668                 exit(-1);
669         }
670
671         __modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info, pkt->cmd);
672         pkg_name = _get_pkgname(menu_info);
673         SECURE_LOGD("pkg name : %s", pkg_name);
674
675         __appid = strdup(pkg_name);
676         aul_set_preinit_appid(__appid);
677         atexit(__release_appid_at_exit);
678
679         __candidate_process_prepare_exec(pkg_name, app_path, menu_info, kb);
680
681         if (out_app_path != NULL && out_argc != NULL && out_argv != NULL)
682         {
683                 int i;
684
685                 sprintf(out_app_path, "%s", app_path);
686
687                 *out_argv = __create_argc_argv(kb, out_argc);
688                 (*out_argv)[0] = out_app_path;
689
690                 for (i = 0; i < *out_argc; i++)
691                 {
692                         SECURE_LOGD("input argument %d : %s##", i, (*out_argv)[i]);
693                 }
694         }
695         else
696         {
697                 exit(-1);
698         }
699
700         if (menu_info != NULL) {
701                 _free_app_info_from_db(menu_info);
702         }
703 }
704
705 static Eina_Bool __candidate_proces_fd_handler(void* data, Ecore_Fd_Handler *handler)
706 {
707         int fd = ecore_main_fd_handler_fd_get(handler);
708
709         if (fd == -1)
710         {
711                 _D("[candidate] ECORE_FD_GET");
712                 exit(-1);
713         }
714
715         if (ecore_main_fd_handler_active_get(handler, ECORE_FD_ERROR))
716         {
717                 _D("[candidate] ECORE_FD_ERROR");
718                 close(fd);
719                 exit(-1);
720         }
721
722         if (ecore_main_fd_handler_active_get(handler, ECORE_FD_READ))
723         {
724                 _D("[candidate] ECORE_FD_READ");
725                 {
726                         app_pkt_t* pkt = (app_pkt_t*) malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
727                         memset(pkt, 0, AUL_SOCK_MAXBUFF);
728
729                         int recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
730                         close(fd);
731                         if (recv_ret == -1)
732                         {
733                                 _D("[condidate] recv error!");
734                                 free(pkt);
735                                 exit(-1);
736                         }
737                         _D("[candidate] recv_ret: %d, pkt->len: %d", recv_ret, pkt->len);
738
739                         ecore_main_fd_handler_del(handler);
740                         __candidate_process_launchpad_main_loop(pkt, g_argv[0], &g_argc, &g_argv);
741                         SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d", g_argv[0], g_argc);
742                         free(pkt);
743                 }
744                 ecore_main_loop_quit();
745                 _D("[candidate] ecore main loop quit");
746         }
747
748         return ECORE_CALLBACK_CANCEL;
749 }
750
751 _static_ void __prepare_candidate_process(int main_fd, int pool_fd, int client_fd)
752 {
753         int pid;
754
755         last_dummy_exec_time = time(NULL);
756
757         pid = fork();
758
759         if (pid == 0) // child
760         {
761                 setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
762                 _D("[candidate] Another candidate process was forked.");
763
764                 //temp - this requires some optimization.
765                 sleep(1);
766                 _D("sleeping 1 sec...");
767
768                 /* Set new session ID & new process group ID*/
769                 /* In linux, child can set new session ID without check permission */
770                 /* TODO : should be add to check permission in the kernel*/
771                 setsid();
772
773                 if (main_fd != -1)
774                 {
775                         close(main_fd);
776                 }
777
778                 if (pool_fd != -1)
779                 {
780                         close(pool_fd);
781                 }
782
783                 if (client_fd != -1)
784                 {
785                         close(client_fd);
786                 }
787
788                 __signal_unset_sigchld();
789                 __signal_fini();
790
791                 /* SET PR_SET_KEEPCAPS */
792                 if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
793                         _E("prctl(PR_SET_KEEPCAPS) failed.");
794                 }
795
796                 /* SET DUMPABLE - for coredump*/
797                 prctl(PR_SET_DUMPABLE, 1);
798                 {
799                         int client_fd = __connect_candidate_process();
800                         if (client_fd == -1)
801                         {
802                                 _D("Connecting to candidate process was failed.");
803                                 exit(-1);
804                         }
805
806                         // Temporarily change HOME path to app
807                         // This change is needed for getting elementary profile
808                         // /opt/home/app/.elementary/config/mobile/base.cfg
809                         setenv(HOME, APP_HOME_PATH, 1);
810                         _D("[candidate] elm_init()");
811                         elm_init(g_argc, g_argv);
812                         setenv(HOME, ROOT_HOME_PATH, 1);
813
814                         Evas_Object *eo = elm_win_add(NULL, "package_name", ELM_WIN_BASIC);
815                         aul_set_preinit_window(eo);
816
817                         Ecore_Fd_Handler* fd_handler = ecore_main_fd_handler_add(client_fd,
818                                                                                    (Ecore_Fd_Handler_Flags)(ECORE_FD_READ|ECORE_FD_ERROR),
819                                                                                    __candidate_proces_fd_handler, NULL, NULL, NULL);
820                         if (fd_handler == NULL)
821                         {
822                                 _D("fd_handler is NULL");
823                                 exit(-1);
824                         }
825
826                         setpriority(PRIO_PROCESS, 0, 0);
827
828                         _D("[candidate] ecore main loop begin");
829                         ecore_main_loop_begin();
830
831                         void *handle = NULL;
832                         int (*dl_main) (int, char **);
833
834                         SECURE_LOGD("[candidate] Launch real application (%s)", g_argv[0]);
835                         handle = dlopen(g_argv[0], RTLD_LAZY | RTLD_GLOBAL);
836                         if (handle == NULL)
837                         {
838                                 _E("dlopen failed (%s).", dlerror());
839                                 exit(-1);
840                         }
841                         dlerror();
842
843                         dl_main = dlsym(handle, "main");
844                         if (dl_main != NULL)
845                         {
846                                 dl_main(g_argc, g_argv);
847                         }
848                         else
849                         {
850                                 _E("dlsym not founded. bad preloaded app - check fpie pie");
851                         }
852
853                         exit(0);
854                 }
855         }
856 }
857
858 static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
859                                                         const char *pkgname, bundle *kb)
860 {
861         app_info_from_db *menu_info;
862
863         menu_info = calloc(1, sizeof(app_info_from_db));
864         if (menu_info == NULL) {
865                 return NULL;
866         }
867
868         menu_info->pkg_name = strdup(pkgname);
869         menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC));
870         if (menu_info->app_path != NULL)
871                 menu_info->original_app_path = strdup(menu_info->app_path);
872         menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE));
873         menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC));
874         menu_info->taskmanage = strdup(bundle_get_val(kb, AUL_K_TASKMANAGE));
875
876         if (!_get_app_path(menu_info)) {
877                 _free_app_info_from_db(menu_info);
878                 return NULL;
879         }
880
881         return menu_info;
882 }
883
884 _static_ void __launchpad_main_loop(int main_fd, int pool_fd)
885 {
886         bundle *kb = NULL;
887         app_pkt_t *pkt = NULL;
888         app_info_from_db *menu_info = NULL;
889
890         const char *pkg_name = NULL;
891         const char *app_path = NULL;
892         int pid = -1;
893         int clifd = -1;
894         struct ucred cr;
895         int is_real_launch = 0;
896
897         char sock_path[UNIX_PATH_MAX] = {0,};
898
899         pkt = __app_recv_raw(main_fd, &clifd, &cr);
900         if (!pkt) {
901                 _D("packet is NULL");
902                 goto end;
903         }
904
905         kb = bundle_decode(pkt->data, pkt->len);
906         if (!kb) {
907                 _D("bundle decode error");
908                 goto end;
909         }
910
911         INIT_PERF(kb);
912         PERF("packet processing start");
913
914         pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
915         SECURE_LOGD("pkg name : %s\n", pkg_name);
916
917         menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
918         if (menu_info == NULL) {
919                 _D("such pkg no found");
920                 goto end;
921         }
922
923         app_path = _get_app_path(menu_info);
924         if(app_path == NULL) {
925                 _E("app_path is NULL");
926                 goto end;
927         }
928         if (app_path[0] != '/') {
929                 _D("app_path is not absolute path");
930                 goto end;
931         }
932
933         __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
934         pkg_name = _get_pkgname(menu_info);
935
936         PERF("get package information & modify bundle done");
937
938         if (candidate_pid != DUMMY_NONE)
939         {
940                 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, candidate_pid);
941                 unlink(sock_path);
942
943                 __candidate_process_real_launch(candidate_fd, pkt);
944                 _D("Request real launch to candidate_process.");
945
946                 pid = candidate_pid;
947                 is_real_launch = 1;
948                 close(candidate_fd);
949
950                 candidate_pid = DUMMY_NONE;
951                 candidate_fd  = -1;
952
953                 /* Temporary log: launch time checking */
954                 //LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
955
956                 __prepare_candidate_process(main_fd, pool_fd, clifd);
957
958                 SECURE_LOGD("Prepare candidate process, pid: %d, bin path: %s\n", pid, app_path);
959         }
960         else
961         {
962                 pid = fork();
963
964                 if (pid == 0)
965                 {
966                         PERF("fork done");
967                         _E("lock up test log(no error) : fork done");
968
969                         close(clifd);
970                         close(main_fd);
971                         __signal_unset_sigchld();
972                         __signal_fini();
973
974                         snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
975                         unlink(sock_path);
976
977                         PERF("prepare exec - first done");
978                         _E("lock up test log(no error) : prepare exec - first done");
979
980                         if (__prepare_exec(pkg_name, app_path,
981                                                            menu_info, kb) < 0)
982                         {
983                                 SECURE_LOGE("preparing work fail to launch - "
984                                    "can not launch %s\n", pkg_name);
985                                 exit(-1);
986                         }
987
988                         PERF("prepare exec - second done");
989                         _E("lock up test log(no error) : prepare exec - second done");
990
991                         __real_launch(app_path, kb);
992
993                         exit(-1);
994                 }
995                 _D("==> real launch pid : %d %s\n", pid, app_path);
996                 is_real_launch = 1;
997         }
998
999  end:
1000         __send_result_to_caller(clifd, pid);
1001
1002         if (pid > 0) {
1003                 if (is_real_launch) {
1004                         /*TODO: retry*/
1005                         __signal_block_sigchld();
1006                         __send_app_launch_signal(pid);
1007                         __signal_unblock_sigchld();
1008                 }
1009         }
1010
1011         if (menu_info != NULL)
1012                 _free_app_info_from_db(menu_info);
1013
1014         if (kb != NULL)
1015                 bundle_free(kb);
1016         if (pkt != NULL)
1017                 free(pkt);
1018
1019         /* Active Flusing for Daemon */
1020         if (initialized > AUL_POLL_CNT) {
1021                 sqlite3_release_memory(SQLITE_FLUSH_MAX);
1022                 malloc_trim(0);
1023                 initialized = 1;
1024         }
1025
1026 }
1027
1028 _static_ int __launchpad_pre_init(int argc, char **argv)
1029 {
1030         int fd;
1031
1032         /* signal init*/
1033         __signal_init();
1034
1035         /* get my(launchpad) command line*/
1036         launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
1037         if (launchpad_cmdline == NULL) {
1038                 _E("launchpad cmdline fail to get");
1039                 return -1;
1040         }
1041         _D("launchpad cmdline = %s", launchpad_cmdline);
1042
1043         /* create launchpad sock */
1044         fd = __create_server_sock(PROCESS_POOL_LAUNCHPAD_PID);
1045         if (fd < 0) {
1046                 _E("server sock error");
1047                 return -1;
1048         }
1049
1050         __preload_init(argc, argv);
1051
1052         __preload_init_for_process_pool();
1053
1054         __preexec_init(argc, argv);
1055
1056         return fd;
1057 }
1058
1059 _static_ int __launchpad_post_init()
1060 {
1061         /* Setting this as a global variable to keep track
1062         of launchpad poll cnt */
1063         /* static int initialized = 0;*/
1064
1065         if (initialized) {
1066                 initialized++;
1067                 return 0;
1068         }
1069
1070         if (__signal_set_sigchld() < 0)
1071                 return -1;
1072
1073         initialized++;
1074
1075         return 0;
1076 }
1077
1078 int main(int argc, char **argv)
1079 {
1080         enum {
1081                 LAUNCH_PAD = 0,
1082                 POOL_SERVER,
1083                 DUMMY_PROCESS,
1084                 POLLFD_MAX
1085         };
1086         int pool_fd = -1;
1087         int main_fd;
1088         struct pollfd pfds[POLLFD_MAX];
1089         int i;
1090
1091         memset(pfds, 0x00, sizeof(pfds));
1092
1093         /* init without concerning X & EFL*/
1094         main_fd = __launchpad_pre_init(argc, argv);
1095         if (main_fd < 0) {
1096                 _E("launchpad pre init failed");
1097                 exit(-1);
1098         }
1099
1100         pfds[LAUNCH_PAD].fd      = main_fd;
1101         pfds[LAUNCH_PAD].events  = POLLIN;
1102         pfds[LAUNCH_PAD].revents = 0;
1103
1104         pool_fd = __create_candidate_process();
1105         if (pool_fd == -1)
1106         {
1107                 _E("Error creationg pool server!");
1108                 goto exit_main;
1109         }
1110
1111         pfds[POOL_SERVER].fd      = pool_fd;
1112         pfds[POOL_SERVER].events  = POLLIN;
1113         pfds[POOL_SERVER].revents = 0;
1114
1115         while (1) {
1116                 if (candidate_pid == DUMMY_NONE)
1117                 {
1118                         pfds[DUMMY_PROCESS].fd          = -1;
1119                         pfds[DUMMY_PROCESS].events  = 0;
1120                         pfds[DUMMY_PROCESS].revents = 0;
1121
1122                         if (DIFF(last_dummy_exec_time, time(NULL)) > EXEC_DUMMY_EXPIRED)
1123                         {
1124                                 __prepare_candidate_process(main_fd, pool_fd, -1);
1125                         }
1126                 }
1127
1128                 if (poll(pfds, POLLFD_MAX, -1) < 0)
1129                         continue;
1130
1131                 _D("pfds[LAUNCH_PAD].revents    : 0x%x", pfds[LAUNCH_PAD].revents) ;
1132                 _D("pfds[POOL_SERVER].revents   : 0x%x", pfds[POOL_SERVER].revents) ;
1133                 _D("pfds[DUMMY_PROCESS].revents : 0x%x", pfds[DUMMY_PROCESS].revents) ;
1134
1135                 /* init with concerning X & EFL (because of booting
1136                 * sequence problem)*/
1137                 if (__launchpad_post_init() < 0)
1138                 {
1139                         _E("launcpad post init failed");
1140                         goto exit_main;
1141                 }
1142
1143                 if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0)
1144                 {
1145                         _D("pfds[LAUNCH_PAD].revents & POLLIN");
1146                         __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pfds[POOL_SERVER].fd);
1147                 }
1148
1149                 if ((pfds[POOL_SERVER].revents & POLLIN) != 0)
1150                 {
1151                         int server_fd, client_fd, client_pid;
1152
1153                         server_fd = pfds[POOL_SERVER].fd;
1154
1155                         _D("pfds[POOL_SERVER].revents & POLLIN");
1156
1157                         if (candidate_pid == DUMMY_NONE)
1158                         {
1159                                 __accept_candidate_process(server_fd, &client_fd, &client_pid);
1160
1161                                 candidate_pid = client_pid;
1162                                 candidate_fd  = client_fd;
1163
1164                                 pfds[DUMMY_PROCESS].fd     = candidate_fd;
1165                                 pfds[DUMMY_PROCESS].events = POLLIN|POLLHUP;
1166                                 pfds[DUMMY_PROCESS].revents = 0;
1167
1168                                 _D("Dummy process was connected! (pid:%d)", candidate_pid);
1169                         }
1170                         else
1171                         {
1172                                 __refuse_candidate_process(server_fd);
1173
1174                                 _E("Refused dummy process connection!");
1175                         }
1176                 }
1177
1178                 if ((pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL)) != 0)
1179                 {
1180                         _D("pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL) (pid:%d)", candidate_pid);
1181
1182                         if (pfds[DUMMY_PROCESS].fd > -1)
1183                         {
1184                                 close(pfds[DUMMY_PROCESS].fd);
1185                         }
1186
1187                         candidate_pid = DUMMY_NONE;
1188                         candidate_fd = -1;
1189
1190                         pfds[DUMMY_PROCESS].fd          = -1;
1191                         pfds[DUMMY_PROCESS].events  = 0;
1192                         pfds[DUMMY_PROCESS].revents = 0;
1193                 }
1194         }
1195
1196         return 0;
1197
1198 exit_main:
1199         if (main_fd != -1)
1200         {
1201                 close(main_fd);
1202         }
1203
1204         if (pool_fd != -1)
1205         {
1206                 close(pool_fd);
1207         }
1208
1209         return -1;
1210 }
1211