60de1e370fa0e70a5fc04800f0594c18e11827a5
[platform/core/appfw/launchpad.git] / src / launchpad.c
1 /*
2  * Copyright (c) 2015 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 <stdlib.h>
20 #include <sys/prctl.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/types.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <stdbool.h>
27 #include <malloc.h>
28 #include <bundle_internal.h>
29 #include <security-manager.h>
30 #include <time.h>
31 #include <vconf.h>
32 #include <systemd/sd-daemon.h>
33 #include <glib.h>
34 #include <linux/limits.h>
35
36 #include "perf.h"
37 #include "launchpad_common.h"
38 #include "sigchild.h"
39 #include "key.h"
40 #include "launchpad.h"
41
42 #define AUL_PR_NAME         16
43 #define EXEC_CANDIDATE_EXPIRED 5
44 #define EXEC_CANDIDATE_WAIT 1
45 #define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
46 #define CANDIDATE_NONE 0
47 #define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock"
48 #define LOADER_PATH_DEFAULT "/usr/bin/launchpad-loader"
49 #define LOADER_PATH_WRT         "/usr/bin/wrt-loader"
50
51 typedef struct {
52         int type;
53         bool prepared;
54         int pid;
55         int loader_id;
56         int caller_pid;
57         int send_fd;
58         int last_exec_time;
59         guint source;
60         guint timer;
61         char *loader_path;
62 } candidate_process_context_t;
63
64 typedef struct {
65         GPollFD *gpollfd;
66         int type;
67         int loader_id;
68 } loader_context_t;
69
70 static GList *candidate_slot_list;
71 static candidate_process_context_t* __add_slot(int type, int loader_id, int caller_pid, const char *loader_path);
72 static int __remove_slot(int type, int loader_id);
73
74 static int __make_loader_id()
75 {
76         static int id = PAD_LOADER_ID_DYNAMIC_BASE;
77
78         return ++id;
79 }
80
81 static candidate_process_context_t* __find_slot_from_static_type(int type)
82 {
83         GList *iter = candidate_slot_list;
84
85         if (type == LAUNCHPAD_TYPE_DYNAMIC || type == LAUNCHPAD_TYPE_UNSUPPORTED)
86                 return NULL;
87
88         while (iter) {
89                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
90                 if (type == cpc->type)
91                         return cpc;
92
93                 iter = g_list_next(iter);
94         }
95
96         return NULL;
97 }
98
99 static candidate_process_context_t* __find_slot_from_pid(int pid)
100 {
101         GList *iter = candidate_slot_list;
102
103         while (iter) {
104                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
105                 if (pid == cpc->pid)
106                         return cpc;
107
108                 iter = g_list_next(iter);
109         }
110
111         return NULL;
112 }
113
114 static candidate_process_context_t* __find_slot_from_caller_pid(int caller_pid)
115 {
116         GList *iter = candidate_slot_list;
117
118         while (iter) {
119                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
120                 if (caller_pid == cpc->caller_pid)
121                         return cpc;
122
123                 iter = g_list_next(iter);
124         }
125
126         return NULL;
127 }
128
129 static candidate_process_context_t* __find_slot_from_loader_id(int id)
130 {
131         GList *iter = candidate_slot_list;
132
133         while (iter) {
134                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
135                 if (id == cpc->loader_id)
136                         return cpc;
137
138                 iter = g_list_next(iter);
139         }
140
141         return NULL;
142 }
143
144 static candidate_process_context_t* __find_slot(int type, int loader_id)
145 {
146         if (type == LAUNCHPAD_TYPE_DYNAMIC)
147                 return __find_slot_from_loader_id(loader_id);
148
149         return __find_slot_from_static_type(type);
150 }
151
152 static void __kill_process(int pid)
153 {
154         char err_str[MAX_LOCAL_BUFSZ] = { 0, };
155
156         if (kill(pid, SIGKILL) == -1)
157                 _E("send SIGKILL: %s", strerror_r(errno, err_str, sizeof(err_str)));
158 }
159
160 static void __refuse_candidate_process(int server_fd)
161 {
162         int client_fd = -1;
163
164         if (server_fd == -1) {
165                 _E("arguments error!");
166                 goto error;
167         }
168
169         client_fd = accept(server_fd, NULL, NULL);
170         if (client_fd == -1) {
171                 _E("accept error!");
172                 goto error;
173         }
174
175         close(client_fd);
176         _D("refuse connection!");
177
178 error:
179         return;
180 }
181
182 static int __accept_candidate_process(int server_fd, int *out_client_fd,
183                 int *out_client_pid)
184 {
185         int client_fd = -1;
186         int client_pid = 0;
187         int recv_ret = 0;
188
189         if (server_fd == -1 || out_client_fd == NULL || out_client_pid == NULL) {
190                 _E("arguments error!");
191                 goto error;
192         }
193
194         client_fd = accept(server_fd, NULL, NULL);
195
196         if (client_fd == -1) {
197                 _E("accept error!");
198                 goto error;
199         }
200
201         recv_ret = recv(client_fd, &client_pid, sizeof(client_pid), MSG_WAITALL);
202
203         if (recv_ret == -1) {
204                 _E("recv error!");
205                 goto error;
206         }
207
208         *out_client_fd = client_fd;
209         *out_client_pid = client_pid;
210
211         return *out_client_fd;
212
213 error:
214         if (client_fd != -1)
215                 close(client_fd);
216
217         return -1;
218 }
219
220 static int __listen_candidate_process(int type, int loader_id)
221 {
222         struct sockaddr_un addr;
223         int fd = -1;
224
225         _D("[launchpad] enter, type: %d", type);
226
227         memset(&addr, 0x00, sizeof(struct sockaddr_un));
228         addr.sun_family = AF_UNIX;
229         snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%d/%s%d-%d", SOCKET_PATH, getuid(),
230                 LAUNCHPAD_LOADER_SOCKET_NAME, type, loader_id);
231
232         fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
233         if (fd < 0) {
234                 _E("Socket error");
235                 goto error;
236         }
237
238         unlink(addr.sun_path);
239
240         _D("bind to %s", addr.sun_path);
241         if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
242                 _E("bind error");
243                 goto error;
244         }
245
246         _D("chmod %s", addr.sun_path);
247         if (chmod(addr.sun_path, (S_IRWXU | S_IRWXG | S_IRWXO)) < 0) {
248                 _E("chmod error");
249                 goto error;
250         }
251
252         _D("listen to %s", addr.sun_path);
253         if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) {
254                 _E("listen error");
255                 goto error;
256         }
257
258         SECURE_LOGD("[launchpad] done, listen fd: %d", fd);
259         return fd;
260
261 error:
262         if (fd != -1)
263                 close(fd);
264
265         return -1;
266 }
267
268 static int __set_access(const char* appId, const char* pkg_type,
269                         const char* app_path)
270 {
271         return security_manager_prepare_app(appId) == SECURITY_MANAGER_SUCCESS ? 0 : -1;
272 }
273
274 static int __get_launchpad_type(const char* internal_pool, const char* hwacc, const char *pkg_type)
275 {
276         int r;
277         int sys_hwacc = -1;
278
279         if (pkg_type && strncmp(pkg_type, "wgt", 3) == 0) {
280                 _D("[launchpad] launchpad type: wrt");
281                 return LAUNCHPAD_TYPE_WRT;
282         }
283
284         if (internal_pool && strncmp(internal_pool, "true", 4) == 0 && hwacc) {
285                 if (strncmp(hwacc, "NOT_USE", 7) == 0) {
286                         _D("[launchpad] launchpad type: S/W(%d)", LAUNCHPAD_TYPE_SW);
287                         return LAUNCHPAD_TYPE_SW;
288                 }
289                 if (strncmp(hwacc, "USE", 3) == 0) {
290                         _D("[launchpad] launchpad type: H/W(%d)", LAUNCHPAD_TYPE_HW);
291                         return LAUNCHPAD_TYPE_HW;
292                 }
293                 if (strncmp(hwacc, "SYS", 3) == 0) {
294                         r = vconf_get_int(VCONFKEY_SETAPPL_APP_HW_ACCELERATION, &sys_hwacc);
295                         if (r != VCONF_OK)
296                                 _E("failed to get vconf int: %s", VCONFKEY_SETAPPL_APP_HW_ACCELERATION);
297
298                         SECURE_LOGD("sys hwacc: %d", sys_hwacc);
299
300                         if (sys_hwacc == SETTING_HW_ACCELERATION_ON) {
301                                 _D("[launchpad] launchpad type: H/W(%d)", LAUNCHPAD_TYPE_HW);
302                                 return LAUNCHPAD_TYPE_HW;
303                         } else if (sys_hwacc == SETTING_HW_ACCELERATION_OFF) {
304                                 _D("[launchpad] launchpad type: S/W(%d)", LAUNCHPAD_TYPE_SW);
305                                 return LAUNCHPAD_TYPE_SW;
306                         }
307                 }
308         }
309
310         _D("[launchpad] launchpad type: COMMON(%d)", LAUNCHPAD_TYPE_COMMON);
311         return LAUNCHPAD_TYPE_COMMON;
312 }
313
314 static int __get_loader_id(bundle *kb)
315 {
316         const char *val;
317
318         val = bundle_get_val(kb, AUL_K_LOADER_ID);
319         if (val == NULL) {
320                 _E("failed to get loader_id");
321                 return -1;
322         }
323
324         return atoi(val);
325 }
326
327 static int __candidate_process_real_launch(int candidate_fd, app_pkt_t *pkt)
328 {
329         return _send_pkt_raw(candidate_fd, pkt);
330 }
331
332 static int __real_send(int clifd, int ret)
333 {
334         if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
335                 if (errno == EPIPE) {
336                         _E("send failed due to EPIPE.\n");
337                         close(clifd);
338                         return -1;
339                 }
340                 _E("send fail to client");
341         }
342
343         close(clifd);
344         return 0;
345 }
346
347 static void __send_result_to_caller(int clifd, int ret, const char* app_path)
348 {
349         char *cmdline;
350
351         _W("Check app launching");
352
353         if (clifd == -1)
354                 return;
355
356         if (ret <= 1) {
357                 _E("launching failed");
358                 __real_send(clifd, ret);
359                 return;
360         }
361
362         cmdline = _proc_get_cmdline_bypid(ret);
363         if (cmdline == NULL) {
364                 _E("The app process might be terminated while we are wating %d", ret);
365                 __real_send(clifd, -1); /* abnormally launched*/
366                 return;
367         }
368
369         if (__real_send(clifd, ret) < 0)
370                 __kill_process(ret);
371
372         return;
373 }
374
375 static int __prepare_candidate_process(int type, int loader_id)
376 {
377         int pid;
378         char type_str[2] = {0, };
379         char loader_id_str[10] = {0, };
380         char *argv[] = {NULL, NULL, NULL, NULL};
381         candidate_process_context_t* cpt = __find_slot(type, loader_id);
382
383         if (cpt == NULL)
384                 return -1;
385
386         cpt->last_exec_time = time(NULL);
387         pid = fork();
388         if (pid == 0) { /* child */
389                 __signal_unblock_sigchld();
390
391                 type_str[0] = '0' + type;
392                 snprintf(loader_id_str, sizeof(loader_id_str), "%d", loader_id);
393                 argv[0] = cpt->loader_path;
394                 argv[1] = type_str;
395                 argv[2] = loader_id_str;
396                 if (execv(argv[0], argv) < 0)
397                         _E("Failed to prepare candidate_process");
398                 else
399                         _D("Succeeded to prepare candidate_process");
400
401                 exit(-1);
402         } else {
403                 cpt->pid = pid;
404         }
405
406         return 0;
407 }
408
409 static gboolean __handle_preparing_candidate_process(gpointer user_data)
410 {
411         candidate_process_context_t *cpc = (candidate_process_context_t*)user_data;
412
413         __prepare_candidate_process(cpc->type, cpc->loader_id);
414         _D("Prepare another candidate process");
415         cpc->timer = 0;
416         return G_SOURCE_REMOVE;
417 }
418
419 static int __send_launchpad_loader(candidate_process_context_t *cpc, app_pkt_t *pkt,
420                                 const char *app_path, int clifd, const char *comp_type)
421 {
422         char sock_path[PATH_MAX];
423         int pid = -1;
424
425         snprintf(sock_path, sizeof(sock_path), "/run/user/%d/%d", getuid(),
426                 cpc->pid);
427         unlink(sock_path);
428
429         __candidate_process_real_launch(cpc->send_fd, pkt);
430         SECURE_LOGD("Request to candidate process, pid: %d, bin path: %s",
431                 cpc->pid, app_path);
432
433         pid = cpc->pid;
434         close(cpc->send_fd);
435
436         cpc->prepared = false;
437         cpc->pid = CANDIDATE_NONE;
438         cpc->send_fd = -1;
439         if (cpc->source > 0) {
440                 g_source_remove(cpc->source);
441                 cpc->source = 0;
442         }
443
444         if (cpc->timer > 0) {
445                 g_source_remove(cpc->timer);
446                 cpc->timer = 0;
447         }
448
449         __send_result_to_caller(clifd, pid, app_path); /* to AMD */
450
451         if (strcmp("uiapp", comp_type) == 0)
452                 cpc->timer = g_timeout_add(5000, __handle_preparing_candidate_process, cpc);
453         else
454                 cpc->timer = g_timeout_add(2000, __handle_preparing_candidate_process, cpc);
455
456         return pid;
457 }
458
459 static int __normal_fork_exec(int argc, char **argv)
460 {
461         _D("start real fork and exec\n");
462
463         if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
464                 if (errno == EACCES)
465                         _E("such a file is no executable - %s", argv[0]);
466                 else
467                         _E("unknown executable error - %s", argv[0]);
468                 return -1;
469         }
470         /* never reach*/
471         return 0;
472 }
473
474 static void __real_launch(const char *app_path, bundle * kb)
475 {
476         int app_argc;
477         char **app_argv;
478         int i;
479
480         if (bundle_get_val(kb, AUL_K_DEBUG) != NULL)
481                 putenv("TIZEN_DEBUGGING_PORT=1");
482
483         app_argv = _create_argc_argv(kb, &app_argc);
484         app_argv[0] = strdup(app_path);
485
486         for (i = 0; i < app_argc; i++) {
487                 if ((i % 2) == 1)
488                         continue;
489                 SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
490         }
491
492         PERF("setup argument done");
493         __normal_fork_exec(app_argc, app_argv);
494 }
495
496 static int __prepare_exec(const char *appId, const char *app_path,
497                         appinfo_t *menu_info, bundle * kb)
498 {
499         char *file_name;
500         char process_name[AUL_PR_NAME];
501         int ret;
502
503         /* Set new session ID & new process group ID*/
504         /* In linux, child can set new session ID without check permission */
505         /* TODO : should be add to check permission in the kernel*/
506         setsid();
507
508         /* SET PRIVILEGES*/
509         if (bundle_get_val(kb, AUL_K_PRIVACY_APPID) == NULL) {
510                 _D("appId: %s / pkg_type : %s / app_path : %s ", appId, menu_info->pkg_type,
511                         app_path);
512                 if ((ret = __set_access(appId, menu_info->pkg_type, app_path)) != 0) {
513                         _D("fail to set privileges - check your package's credential : %d\n", ret);
514                         return -1;
515                 }
516         }
517         /* SET DUMPABLE - for coredump*/
518         prctl(PR_SET_DUMPABLE, 1);
519
520         /* SET PROCESS NAME*/
521         if (app_path == NULL) {
522                 _D("app_path should not be NULL - check menu db");
523                 return -1;
524         }
525         file_name = strrchr(app_path, '/') + 1;
526         if (file_name == NULL) {
527                 _D("can't locate file name to execute");
528                 return -1;
529         }
530         memset(process_name, '\0', AUL_PR_NAME);
531         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
532         prctl(PR_SET_NAME, process_name);
533
534         /* SET ENVIROMENT*/
535         _set_env(menu_info, kb);
536
537         return 0;
538 }
539
540 static int __launch_directly(const char *appid, const char *app_path, int clifd,
541                                 bundle* kb, appinfo_t *menu_info)
542 {
543         char sock_path[PATH_MAX];
544         int pid = fork();
545         int max_fd;
546         int iter_fd;
547
548         if (pid == 0) {
549                 PERF("fork done");
550                 _D("lock up test log(no error) : fork done");
551
552                 __signal_unblock_sigchld();
553                 __signal_fini();
554
555                 max_fd = sysconf(_SC_OPEN_MAX);
556                 for (iter_fd = 3; iter_fd <= max_fd; iter_fd++)
557                         close(iter_fd);
558
559                 snprintf(sock_path, sizeof(sock_path), "/run/user/%d/%d", getuid(), getpid());
560                 unlink(sock_path);
561
562                 PERF("prepare exec - first done");
563                 _D("lock up test log(no error) : prepare exec - first done");
564
565                 if (__prepare_exec(appid, app_path,
566                                 menu_info, kb) < 0) {
567                         SECURE_LOGE("preparing work fail to launch - "
568                                 "can not launch %s\n", appid);
569                         exit(-1);
570                 }
571
572                 PERF("prepare exec - second done");
573                 _D("lock up test log(no error) : prepare exec - second done");
574                 __real_launch(app_path, kb);
575
576                 exit(-1);
577         }
578         SECURE_LOGD("==> real launch pid : %d %s\n", pid, app_path);
579
580         return pid;
581 }
582
583 static int __create_sock_activation(void)
584 {
585         int fds;
586
587         fds = sd_listen_fds(0);
588         if (fds == 1)
589                 return SD_LISTEN_FDS_START;
590         else if (fds > 1)
591                 _E("Too many file descriptors received.\n");
592         else
593                 _D("There is no socket stream");
594
595         return -1;
596 }
597
598 static int __launchpad_pre_init(int argc, char **argv)
599 {
600         int fd;
601
602         /* signal init*/
603         __signal_init();
604
605         /* create launchpad sock */
606         fd = __create_sock_activation();
607         if (fd < 0) {
608                 fd = _create_server_sock(PROCESS_POOL_LAUNCHPAD_SOCK);
609                 if (fd < 0) {
610                         _E("server sock error %d", fd);
611                         return -1;
612                 }
613         }
614
615         return fd;
616 }
617
618 static void __destroy_poll_data(gpointer data)
619 {
620         free(data);
621 }
622
623 static gboolean __glib_check(GSource *src)
624 {
625         GSList *fd_list;
626         GPollFD *tmp;
627
628         fd_list = src->poll_fds;
629         do {
630                 tmp = (GPollFD *) fd_list->data;
631                 if ((tmp->revents & (G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_NVAL)))
632                         return TRUE;
633                 fd_list = fd_list->next;
634         } while (fd_list);
635
636         return FALSE;
637 }
638
639 static gboolean __glib_dispatch(GSource *src, GSourceFunc callback,
640                 gpointer data)
641 {
642         return callback(data);
643 }
644
645 static gboolean __glib_prepare(GSource *src, gint *timeout)
646 {
647         return FALSE;
648 }
649
650 static GSourceFuncs funcs = {
651         .prepare = __glib_prepare,
652         .check = __glib_check,
653         .dispatch = __glib_dispatch,
654         .finalize = NULL
655 };
656
657 static int __poll_fd(int fd, gushort events, GSourceFunc func, int type, int loader_id)
658 {
659         int r;
660         GPollFD *gpollfd;
661         GSource *src;
662
663         src = g_source_new(&funcs, sizeof(GSource));
664         if (!src) {
665                 _E("out of memory");
666                 return -1;
667         }
668
669         gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD));
670         if (!gpollfd) {
671                 _E("out of memory");
672                 g_source_destroy(src);
673                 return -1;
674         }
675
676         gpollfd->events = events;
677         gpollfd->fd = fd;
678
679         loader_context_t *lc = malloc(sizeof(loader_context_t));
680         if (lc == NULL) {
681                 g_free(gpollfd);
682                 g_source_destroy(src);
683                 return -1;
684         }
685
686         lc->gpollfd = gpollfd;
687         lc->type = type;
688         lc->loader_id = loader_id;
689
690         g_source_add_poll(src, gpollfd);
691         g_source_set_callback(src, func,
692                         (gpointer) lc, __destroy_poll_data);
693         g_source_set_priority(src, G_PRIORITY_DEFAULT);
694
695         r = g_source_attach(src, NULL);
696         if (r  == 0) {
697                 g_free(gpollfd);
698                 g_source_destroy(src);
699                 return -1;
700         }
701
702         return r;
703 }
704
705 static gboolean __handle_loader_client_event(gpointer data)
706 {
707         loader_context_t *lc = (loader_context_t*) data;
708         int type = lc->type;
709         int loader_id = lc->loader_id;
710         gushort revents = lc->gpollfd->revents;
711
712         candidate_process_context_t *cpc = __find_slot(type, loader_id);
713
714         if (cpc == NULL)
715                 return G_SOURCE_REMOVE;
716
717         if (revents & (G_IO_HUP | G_IO_NVAL)) {
718                 SECURE_LOGE("Type %d candidate process was (POLLHUP|POLLNVAL), pid: %d", cpc->type,
719                                 cpc->pid);
720                 close(cpc->send_fd);
721
722                 cpc->prepared = false;
723                 cpc->pid = CANDIDATE_NONE;
724                 cpc->send_fd = -1;
725                 cpc->source = 0;
726                 if (cpc->timer > 0)
727                         g_source_remove(cpc->timer);
728                 cpc->timer = 0;
729                 __prepare_candidate_process(cpc->type, cpc->loader_id);
730
731                 return G_SOURCE_REMOVE;
732         }
733
734         return G_SOURCE_CONTINUE;
735 }
736
737 static gboolean __handle_loader_event(gpointer data)
738 {
739         loader_context_t *lc = (loader_context_t*) data;
740         int fd = lc->gpollfd->fd;
741         int type = lc->type;
742         int loader_id = lc->loader_id;
743         int client_fd;
744         int client_pid;
745
746         candidate_process_context_t *cpc = __find_slot(type, loader_id);
747
748         if (cpc == NULL)
749                 return G_SOURCE_REMOVE;
750
751         if (!cpc->prepared) {
752                 if (__accept_candidate_process(fd, &client_fd, &client_pid) >= 0) {
753                         cpc->prepared = true;
754                         cpc->send_fd = client_fd;
755
756                         SECURE_LOGD("Type %d candidate process was connected, pid: %d", type,
757                                         cpc->pid);
758
759                         cpc->source = __poll_fd(client_fd, G_IO_IN | G_IO_HUP,
760                                                         (GSourceFunc)__handle_loader_client_event, type, loader_id);
761                         if (cpc->source < 0)
762                                 close(client_fd);
763                 }
764         } else {
765                 __refuse_candidate_process(fd);
766                 _E("Refused candidate process connection");
767         }
768
769         return G_SOURCE_CONTINUE;
770 }
771
772 static gboolean __handle_sigchild(gpointer data)
773 {
774         loader_context_t *lc = (loader_context_t*) data;
775         int fd = lc->gpollfd->fd;
776         struct signalfd_siginfo siginfo;
777         ssize_t s;
778
779         do {
780                 s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
781                 if (s == 0)
782                         break;
783
784                 if (s != sizeof(struct signalfd_siginfo)) {
785                         _E("error reading sigchld info");
786                         break;
787                 }
788                 __launchpad_process_sigchld(&siginfo);
789                 candidate_process_context_t *cpc = __find_slot_from_pid(siginfo.ssi_pid);
790
791                 if (cpc != NULL) {
792                         cpc->prepared = false;
793                         __prepare_candidate_process(cpc->type, cpc->loader_id);
794                 }
795
796                 cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
797                 while (cpc) {
798                         __remove_slot(LAUNCHPAD_TYPE_DYNAMIC, cpc->loader_id);
799                         cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
800                 }
801
802         } while (s > 0);
803
804         return G_SOURCE_CONTINUE;
805 }
806
807 static int __dispatch_cmd_visibility(bundle *kb)
808 {
809         GList *iter = candidate_slot_list;
810
811         _W("cmd visibility");
812         while (iter) {
813                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
814
815                 if (cpc->pid == CANDIDATE_NONE) {
816                         if (cpc->timer > 0) {
817                                 g_source_remove(cpc->timer);
818                                 cpc->timer = 0;
819                         }
820                         __prepare_candidate_process(cpc->type, cpc->loader_id);
821                 }
822
823                 iter = g_list_next(iter);
824         }
825
826         return 0;
827 }
828
829 static int __dispatch_cmd_add_loader(bundle *kb)
830 {
831         const char *add_slot_str = NULL;
832         const char *caller_pid = NULL;
833         int lid;
834
835         _W("cmd add loader");
836         add_slot_str = bundle_get_val(kb, AUL_K_LOADER_PATH);
837         caller_pid = bundle_get_val(kb, AUL_K_CALLER_PID);
838
839         if (add_slot_str && caller_pid) {
840                 lid = __make_loader_id();
841                 candidate_process_context_t *cpc = __add_slot(LAUNCHPAD_TYPE_DYNAMIC, lid, atoi(caller_pid), add_slot_str);
842                 if (cpc)
843                         cpc->timer = g_timeout_add(2000, __handle_preparing_candidate_process, cpc);
844
845                 return lid;
846         }
847
848         return -1;
849 }
850
851 static int __dispatch_cmd_remove_loader(bundle *kb)
852 {
853         const char *id = bundle_get_val(kb, AUL_K_LOADER_ID);
854         int lid;
855
856         _W("cmd remove loader");
857         if (id) {
858                 lid = atoi(id);
859                 if (__remove_slot(LAUNCHPAD_TYPE_DYNAMIC, lid) == 0)
860                         return 0;
861         }
862
863         return -1;
864 }
865
866 static gboolean __handle_launch_event(gpointer data)
867 {
868         loader_context_t *lc = (loader_context_t*) data;
869         int fd = lc->gpollfd->fd;
870         bundle *kb = NULL;
871         app_pkt_t *pkt = NULL;
872         appinfo_t *menu_info = NULL;
873         candidate_process_context_t *cpc;
874
875         const char *app_path = NULL;
876         int pid = -1;
877         int clifd = -1;
878         struct ucred cr;
879         int type = -1;
880         int loader_id;
881         int ret;
882
883         pkt = _recv_pkt_raw(fd, &clifd, &cr);
884         if (!pkt) {
885                 _E("packet is NULL");
886                 goto end;
887         }
888
889         kb = bundle_decode(pkt->data, pkt->len);
890         if (!kb) {
891                 _E("bundle decode error");
892                 goto end;
893         }
894
895         switch (pkt->cmd) {
896         case PAD_CMD_VISIBILITY:
897                 ret = __dispatch_cmd_visibility(kb);
898                 __real_send(clifd, ret);
899                 clifd = -1;
900                 goto end;
901         case PAD_CMD_ADD_LOADER:
902                 ret = __dispatch_cmd_add_loader(kb);
903                 __real_send(clifd, ret);
904                 clifd = -1;
905                 goto end;
906         case PAD_CMD_REMOVE_LOADER:
907                 ret = __dispatch_cmd_remove_loader(kb);
908                 __real_send(clifd, ret);
909                 clifd = -1;
910                 goto end;
911         }
912
913         INIT_PERF(kb);
914         PERF("packet processing start");
915
916         menu_info = _appinfo_create(kb);
917         if (menu_info == NULL) {
918                 _E("such pkg no found");
919                 goto end;
920         }
921
922         app_path = _appinfo_get_app_path(menu_info);
923         if (app_path == NULL) {
924                 _E("app_path is NULL");
925                 goto end;
926         }
927         if (app_path[0] != '/') {
928                 _E("app_path is not absolute path");
929                 goto end;
930         }
931
932         if (menu_info->hwacc == NULL) {
933                 _E("[launchpad] Failed to find H/W acceleration type");
934                 goto end;
935         }
936
937         SECURE_LOGD("exec : %s\n", menu_info->app_path);
938         SECURE_LOGD("comp_type : %s\n", menu_info->comp_type);
939         SECURE_LOGD("internal pool : %s\n", menu_info->internal_pool);
940         SECURE_LOGD("hwacc : %s\n", menu_info->hwacc);
941         SECURE_LOGD("pkg_type : %s\n", menu_info->pkg_type);
942
943         if ((loader_id = __get_loader_id(kb)) <= PAD_LOADER_ID_STATIC) {
944                 type = __get_launchpad_type(menu_info->internal_pool, menu_info->hwacc, menu_info->pkg_type);
945                 if (type < 0) {
946                         _E("failed to get launchpad type");
947                         goto end;
948                 }
949                 loader_id = PAD_LOADER_ID_STATIC;
950         } else {
951                 type = LAUNCHPAD_TYPE_DYNAMIC;
952         }
953
954         _modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
955         if (menu_info->appid == NULL) {
956                 _E("unable to get appid from menu_info");
957                 goto end;
958         }
959
960         PERF("get package information & modify bundle done");
961
962         if (loader_id == PAD_LOADER_ID_DIRECT ||
963                 (cpc = __find_slot(type, loader_id)) == NULL) {
964                 _W("Launch directly");
965                 pid = __launch_directly(menu_info->appid, app_path, clifd, kb, menu_info);
966         } else {
967                 if (cpc->prepared) {
968                         _W("Launch %d type process", type);
969                         pid = __send_launchpad_loader(cpc, pkt, app_path, clifd, menu_info->comp_type);
970                 } else if (cpc->type == LAUNCHPAD_TYPE_SW || cpc->type == LAUNCHPAD_TYPE_HW) {
971                                 cpc = __find_slot(LAUNCHPAD_TYPE_COMMON, loader_id);
972                                 if (cpc != NULL && cpc->prepared) {
973                                         _W("Launch common type process");
974                                         pid = __send_launchpad_loader(cpc, pkt, app_path, clifd, menu_info->comp_type);
975                                 } else {
976                                         _W("Launch directly");
977                                         pid = __launch_directly(menu_info->appid, app_path, clifd, kb, menu_info);
978                                 }
979                 } else {
980                         _W("Launch directly");
981                         pid = __launch_directly(menu_info->appid, app_path, clifd, kb, menu_info);
982                 }
983         }
984
985         __send_result_to_caller(clifd, pid, app_path);
986         clifd = -1;
987 end:
988         if (clifd != -1)
989                 close(clifd);
990
991         if (pid > 0)
992                 __send_app_launch_signal_dbus(pid, menu_info->appid);
993
994         if (menu_info != NULL)
995                 _appinfo_free(menu_info);
996
997         if (kb != NULL)
998                 bundle_free(kb);
999         if (pkt != NULL)
1000                 free(pkt);
1001
1002         return G_SOURCE_CONTINUE;
1003 }
1004
1005 static candidate_process_context_t* __add_slot(int type, int loader_id, int caller_pid, const char *loader_path)
1006 {
1007         candidate_process_context_t *cpc;
1008         int fd = -1;
1009
1010         if (__find_slot(type, loader_id) != NULL)
1011                 return NULL;
1012
1013         cpc = (candidate_process_context_t*)malloc(sizeof(candidate_process_context_t));
1014         if (cpc == NULL)
1015                 return NULL;
1016
1017         cpc->type = type;
1018         cpc->prepared = false;
1019         cpc->pid = CANDIDATE_NONE;
1020         cpc->caller_pid = caller_pid;
1021         cpc->loader_id = loader_id;
1022         cpc->send_fd = -1;
1023         cpc->last_exec_time = 0;
1024         cpc->source = 0;
1025         cpc->timer = 0;
1026         cpc->loader_path = strdup(loader_path);
1027
1028         fd = __listen_candidate_process(cpc->type, cpc->loader_id);
1029         if (fd == -1) {
1030                 _E("[launchpad] Listening the socket to the type %d candidate process failed.",
1031                    cpc->type);
1032                 free(cpc);
1033                 return NULL;
1034         }
1035
1036         if (__poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_loader_event, cpc->type, cpc->loader_id) < 0) {
1037                 close(fd);
1038                 free(cpc);
1039                 return NULL;
1040         }
1041
1042         candidate_slot_list = g_list_append(candidate_slot_list, cpc);
1043
1044         return cpc;
1045 }
1046
1047 static int __remove_slot(int type, int loader_id)
1048 {
1049         GList *iter;
1050         iter = candidate_slot_list;
1051
1052         while (iter) {
1053                 candidate_process_context_t *cpc = (candidate_process_context_t*)iter->data;
1054
1055                 if (type == cpc->type && loader_id == cpc->loader_id) {
1056                         if (cpc->pid > 0)
1057                                 __kill_process(cpc->pid);
1058                         if (cpc->timer > 0)
1059                                 g_source_remove(cpc->timer);
1060                         if (cpc->source > 0)
1061                                 g_source_remove(cpc->source);
1062
1063                         candidate_slot_list = g_list_remove_link(candidate_slot_list, iter);
1064                         free(cpc->loader_path);
1065                         free(cpc);
1066                         return 0;
1067                 }
1068
1069                 iter = g_list_next(iter);
1070         }
1071
1072         return -1;
1073 }
1074
1075 static int __init_launchpad_fd(int argc, char **argv)
1076 {
1077         int fd = -1;
1078
1079         fd = __launchpad_pre_init(argc, argv);
1080         if (fd < 0) {
1081                 _E("launchpad pre init failed");
1082                 return -1;
1083         }
1084
1085         if (__poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_launch_event, 0, 0) < 0) {
1086                 close(fd);
1087                 return -1;
1088         }
1089
1090         return 0;
1091 }
1092
1093 static int __init_sigchild_fd(void)
1094 {
1095         int fd = -1;
1096
1097         fd = __signal_get_sigchld_fd();
1098         if (fd < 0) {
1099                 _E("failed to get sigchld fd");
1100                 return -1;
1101         }
1102
1103         if (__poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_sigchild, 0, 0) < 0) {
1104                 close(fd);
1105                 return -1;
1106         }
1107
1108         return 0;
1109 }
1110
1111 static int __add_default_slots()
1112 {
1113         if (__add_slot(LAUNCHPAD_TYPE_COMMON, PAD_LOADER_ID_STATIC, 0, LOADER_PATH_DEFAULT) == NULL)
1114                 return -1;
1115         if (__prepare_candidate_process(LAUNCHPAD_TYPE_COMMON, PAD_LOADER_ID_STATIC) != 0)
1116                 return -1;
1117
1118         if (__add_slot(LAUNCHPAD_TYPE_SW, PAD_LOADER_ID_STATIC, 0, LOADER_PATH_DEFAULT) == NULL)
1119                 return -1;
1120         if (__prepare_candidate_process(LAUNCHPAD_TYPE_SW, PAD_LOADER_ID_STATIC) != 0)
1121                 return -1;
1122
1123         if (__add_slot(LAUNCHPAD_TYPE_HW, PAD_LOADER_ID_STATIC, 0, LOADER_PATH_DEFAULT) == NULL)
1124                 return -1;
1125         if (__prepare_candidate_process(LAUNCHPAD_TYPE_HW, PAD_LOADER_ID_STATIC) != 0)
1126                 return -1;
1127
1128         if (access(LOADER_PATH_WRT, F_OK | X_OK) == 0) {
1129                 if (__add_slot(LAUNCHPAD_TYPE_WRT, PAD_LOADER_ID_STATIC, 0, LOADER_PATH_WRT) == NULL)
1130                         return -1;
1131                 if (__prepare_candidate_process(LAUNCHPAD_TYPE_WRT, PAD_LOADER_ID_STATIC) != 0)
1132                         return -1;
1133         }
1134
1135         return 0;
1136 }
1137
1138 static int __before_loop(int argc, char **argv)
1139 {
1140         if (__init_sigchild_fd() != 0) {
1141                 _E("__init_sigchild_fd() failed");
1142                 return -1;
1143         }
1144
1145         if (__init_launchpad_fd(argc, argv) != 0) {
1146                 _E("__init_launchpad_fd() failed");
1147                 return -1;
1148         }
1149
1150         if (__add_default_slots() != 0) {
1151                 _E("__add_default_slots() failed");
1152                 return -1;
1153         }
1154
1155         return 0;
1156 }
1157
1158 #ifdef _APPFW_FEATURE_PRIORITY_CHANGE
1159 static void __set_priority(void)
1160 {
1161         char err_str[MAX_LOCAL_BUFSZ] = { 0, };
1162         int res = setpriority(PRIO_PROCESS, 0, -12);
1163
1164         if (res == -1)
1165                 SECURE_LOGE("Setting process (%d) priority to -12 failed, errno: %d (%s)",
1166                         getpid(), errno, strerror_r(errno, err_str, sizeof(err_str)));
1167 }
1168 #endif
1169
1170 int main(int argc, char **argv)
1171 {
1172         GMainLoop *mainloop = NULL;
1173
1174         mainloop = g_main_loop_new(NULL, FALSE);
1175         if (!mainloop) {
1176                 _E("failed to create glib main loop");
1177                 return -1;
1178         }
1179
1180         if (__before_loop(argc, argv) != 0) {
1181                 _E("process-pool Initialization failed!\n");
1182                 return -1;
1183         }
1184
1185 #ifdef _APPFW_FEATURE_PRIORITY_CHANGE
1186         __set_priority();
1187 #endif
1188         g_main_loop_run(mainloop);
1189
1190         return -1;
1191 }