2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * simple AUL daemon - launchpad
25 #include <sys/types.h>
30 #include <sys/prctl.h>
32 #include <sys/resource.h>
40 #include "menu_db_util.h"
41 #include "simple_util.h"
42 #include "access_control.h"
47 #include <app-checker.h>
50 #include "process_pool.h"
51 #include "launchpad_util.h"
53 #if ENABLE(PRE_LAUNCH)
54 #include "pre_launching.h"
57 #define _static_ static inline
58 #define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
59 #define AUL_POLL_CNT 15
60 #define AUL_PR_NAME 16
61 #define PKG_ID_LENGTH 11
63 #define EXEC_DUMMY_EXPIRED 5
64 #define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a))
65 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
66 #define LOWEST_PRIO 20
69 static char *launchpad_cmdline;
70 static int initialized = 0;
71 static int dummy_process_pid = DUMMY_NONE;
72 static int dummy_process_fd = -1;
73 static int last_dummy_exec_time = 0;
74 static int process_pool_disable = 0;
76 _static_ int __prepare_exec(const char *pkg_name,
77 const char *app_path, app_info_from_db * menu_info,
79 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
80 _static_ char **__create_argc_argv(bundle * kb, int *margc);
81 _static_ void __real_launch(const char *app_path, bundle * kb);
82 _static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt);
83 _static_ int __send_to_sigkill(int pid);
84 _static_ int __term_app(int pid);
85 _static_ int __real_send(int clifd, int ret);
86 _static_ void __send_result_to_caller(int clifd, int ret);
87 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd);
88 _static_ void __launchpad_main_loop(int main_fd, int pool_fd);
89 _static_ int __launchpad_pre_init(int argc, char **argv);
90 _static_ int __launchpad_post_init();
92 extern ail_error_e ail_db_close(void);
94 _static_ int __prepare_exec(const char *pkg_name,
95 const char *app_path, app_info_from_db * menu_info,
98 const char* file_name;
99 char process_name[AUL_PR_NAME];
101 /* Set new session ID & new process group ID*/
102 /* In linux, child can set new session ID without check permission */
103 /* TODO : should be add to check permission in the kernel*/
106 __preexec_run(menu_info->pkg_type, pkg_name, app_path);
109 char pkg_id[PKG_ID_LENGTH];
110 memset(pkg_id, '\0', PKG_ID_LENGTH);
111 snprintf(pkg_id, PKG_ID_LENGTH, "%s", pkg_name);
113 /* SET PR_SET_KEEPCAPS */
114 if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
115 WrtLogE("prctl(PR_SET_KEEPCAPS) failed.");
118 if (AccessControl::setPriviledge(pkg_id, menu_info->pkg_type, app_path) < 0) {
119 WrtLogD("fail to set privileges - check your package's credential\n");
123 __set_inherit_bit_for_CAP_MAC_ADMIN();
125 /* SET DUMPABLE - for coredump*/
126 prctl(PR_SET_DUMPABLE, 1);
128 /* SET PROCESS NAME*/
129 if (app_path == NULL) {
130 WrtLogD("app_path should not be NULL - check menu db");
133 file_name = strrchr(app_path, '/');
134 if (file_name == NULL) {
135 WrtLogD("can't locate file name to execute");
138 memset(process_name, '\0', AUL_PR_NAME);
139 snprintf(process_name, AUL_PR_NAME, "%s", file_name + 1);
140 prctl(PR_SET_NAME, process_name);
143 __set_env(menu_info, kb);
148 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
154 bundle_encode(kb, &kb_data, &datalen);
155 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
156 WrtLogE("error request fake launch - error code = %d", ret);
162 _static_ void __real_launch(const char *app_path, bundle * kb)
168 app_argv = __create_argc_argv(kb, &app_argc);
170 #ifndef NATIVE_LAUNCHPAD
171 if (__change_cmdline((char *)app_path) < 0) {
172 WrtLogE("change cmdline fail");
176 app_argv[0] = g_argv[0];
178 app_argv[0] = strdup(app_path);
181 for (i = 0; i < app_argc; i++) {
182 WrtLogD("input argument %d : %s##", i, app_argv[i]);
185 WrtLogE("lock up test log(no error) : setup argument done");
187 /* Temporary log: launch time checking */
188 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
190 __preload_exec(app_argc, app_argv);
193 _static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt)
195 return __send_pkt_raw_data(dummy_client_fd, pkt);
198 _static_ int __send_to_sigkill(int pid)
207 if (killpg(pgid, SIGKILL) < 0) {
214 _static_ int __term_app(int pid)
218 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0)
220 WrtLogD("terminate packet send error - use SIGKILL");
221 if (__send_to_sigkill(pid) < 0) {
222 WrtLogE("fail to killing - %d\n", pid);
226 WrtLogD("term done\n");
230 static int __get_caller_pid(bundle *kb)
235 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
240 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
241 if (pid_str == NULL) {
254 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
257 char tmp_pid[MAX_PID_STR_BUFSZ];
262 if ((pid = __get_caller_pid(kb)) < 0) {
266 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
268 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
270 bundle_encode(kb, &kb_data, &datalen);
271 if ((res = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
280 _static_ int __real_send(int clifd, int ret)
282 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
283 if (errno == EPIPE) {
284 WrtLogE("send failed due to EPIPE.\n");
288 WrtLogE("send fail to client");
295 _static_ void __send_result_to_caller(int clifd, int ret)
299 int cmdline_changed = 0;
300 int cmdline_exist = 0;
308 __real_send(clifd, ret);
311 /* check normally was launched?*/
314 cmdline = __proc_get_cmdline_bypid(ret);
315 if (cmdline == NULL) {
316 WrtLogE("error founded when being launched with %d", ret);
317 } else if (strcmp(cmdline, launchpad_cmdline)) {
326 WrtLogD("-- now wait to change cmdline --");
327 struct timespec duration = { 0, 50 * 1000 * 1000 };
328 nanosleep(&duration, NULL); /* 50ms sleep*/
330 } while (wait_count <= 20); /* max 50*20ms will be sleep*/
332 if ((!cmdline_exist) && (!cmdline_changed)) {
333 __real_send(clifd, -1); /* abnormally launched*/
337 if (!cmdline_changed) {
338 WrtLogE("process launched, but cmdline not changed");
341 if (__real_send(clifd, ret) < 0) {
342 r = kill(ret, SIGKILL);
344 WrtLogE("send SIGKILL: %s", strerror(errno));
351 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd)
355 last_dummy_exec_time = time(NULL);
359 if (pid == 0) // child
361 setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
362 WrtLogD("Launch dummy process...");
364 //temp - this requires some optimization.
366 WrtLogD("sleeping 1 sec...");
368 /* Set new session ID & new process group ID*/
369 /* In linux, child can set new session ID without check permission */
370 /* TODO : should be add to check permission in the kernel*/
388 __signal_unset_sigchld();
391 /* SET PR_SET_KEEPCAPS */
392 if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
393 WrtLogE("prctl(PR_SET_KEEPCAPS) failed.");
396 /* SET DUMPABLE - for coredump*/
397 prctl(PR_SET_DUMPABLE, 1);
401 int (*dl_main) (int, char **);
403 handle = dlopen(WRT_CLIENT_PATH, RTLD_NOW | RTLD_GLOBAL);
407 WrtLogE("dlopen failed.");
411 dl_main = reinterpret_cast<int (*)(int, char **)>(dlsym(handle, "main"));
413 sprintf(g_argv[1], "%s", "-d");
417 dl_main(g_argc, g_argv);
421 WrtLogE("dlsym not founded. bad preloaded app - check fpie pie");
429 _static_ void __launchpad_main_loop(int main_fd, int pool_fd)
432 app_pkt_t *pkt = NULL;
433 app_info_from_db *menu_info = NULL;
435 const char *pkg_name = NULL;
436 const char *app_path = NULL;
440 int is_real_launch = 0;
442 char sock_path[UNIX_PATH_MAX] = { 0, };
444 pkt = __app_recv_raw(main_fd, &clifd, &cr);
446 WrtLogD("packet is NULL");
450 kb = bundle_decode(pkt->data, pkt->len);
452 WrtLogD("bundle decode error");
456 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
457 SECURE_LOGD("pkg name : %s\n", pkg_name);
459 menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
460 if (menu_info == NULL) {
461 WrtLogD("such pkg no found");
465 app_path = _get_app_path(menu_info);
466 if (app_path == NULL) {
467 WrtLogE("app_path is NULL");
470 if (app_path[0] != '/') {
471 WrtLogD("app_path is not absolute path");
475 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
476 pkg_name = _get_pkgname(menu_info);
478 if (dummy_process_pid != DUMMY_NONE)
480 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, dummy_process_pid);
483 __dummy_launch(dummy_process_fd, pkt);
485 pid = dummy_process_pid;
487 close(dummy_process_fd);
489 dummy_process_pid = DUMMY_NONE;
490 dummy_process_fd = -1;
492 /* Temporary log: launch time checking */
493 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
495 __launchpad_exec_dummy(main_fd, pool_fd, clifd);
497 WrtLogD("==> dummy launch pid : %d %s\n", pid, app_path);
505 WrtLogE("lock up test log(no error) : fork done");
509 __signal_unset_sigchld();
512 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
515 WrtLogE("lock up test log(no error) : prepare exec - first done");
517 if (__prepare_exec(pkg_name, app_path,
520 SECURE_LOGE("preparing work fail to launch - "
521 "can not launch %s\n", pkg_name);
525 WrtLogE("lock up test log(no error) : prepare exec - second done");
527 __real_launch(app_path, kb);
531 WrtLogD("==> real launch pid : %d %s\n", pid, app_path);
536 __send_result_to_caller(clifd, pid);
539 if (is_real_launch) {
541 __signal_block_sigchld();
542 __send_app_launch_signal(pid);
544 #if ENABLE(PRE_LAUNCH)
545 if (is_pre_launching_appid(pkg_name)) {
546 add_to_pre_launching_info_list(pkg_name, pid);
549 __signal_unblock_sigchld();
553 if (menu_info != NULL) {
554 _free_app_info_from_db(menu_info);
564 /* Active Flusing for Daemon */
565 if (initialized > AUL_POLL_CNT) {
566 sqlite3_release_memory(SQLITE_FLUSH_MAX);
572 _static_ int __launchpad_pre_init(int argc, char **argv)
579 /* get my(launchpad) command line*/
580 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
581 if (launchpad_cmdline == NULL) {
582 WrtLogE("launchpad cmdline fail to get");
585 WrtLogD("launchpad cmdline = %s", launchpad_cmdline);
587 /* create launchpad sock */
588 fd = __create_server_sock(WRT_LAUNCHPAD_PID);
590 WrtLogE("server sock error");
594 __preload_init(argc, argv);
596 __preload_init_for_wrt();
598 __preexec_init(argc, argv);
603 _static_ int __launchpad_post_init()
605 /* Setting this as a global variable to keep track
606 * of launchpad poll cnt */
607 /* static int initialized = 0;*/
614 if (__signal_set_sigchld() < 0) {
623 int main(int argc, char **argv)
632 int main_fd = -1, pool_fd = -1;
633 struct pollfd pfds[POLLFD_MAX];
635 memset(pfds, 0x00, sizeof(pfds));
637 #if ENABLE(PRE_LAUNCH)
638 pre_launch_webapps();
641 // process pool feature disable
642 if (getenv("WRT_PROCESS_POOL_DISABLE"))
644 process_pool_disable = 1;
647 /* init without concerning X & EFL*/
648 main_fd = __launchpad_pre_init(argc, argv);
652 WrtLogE("launchpad pre init failed");
656 pfds[LAUNCH_PAD].fd = main_fd;
657 pfds[LAUNCH_PAD].events = POLLIN;
658 pfds[LAUNCH_PAD].revents = 0;
660 pool_fd = __create_process_pool_server();
664 WrtLogE("Error creationg pool server!");
668 pfds[POOL_SERVER].fd = pool_fd;
669 pfds[POOL_SERVER].events = POLLIN;
670 pfds[POOL_SERVER].revents = 0;
673 // This is temporary code to delay creating dummy process.
674 // It will make that a dummy_process is created on first webapp launching.
675 last_dummy_exec_time = time(NULL);
679 if (dummy_process_pid == DUMMY_NONE)
681 pfds[DUMMY_PROCESS].fd = -1;
682 pfds[DUMMY_PROCESS].events = 0;
683 pfds[DUMMY_PROCESS].revents = 0;
685 if ( !process_pool_disable &&
686 DIFF(last_dummy_exec_time, time(NULL)) > EXEC_DUMMY_EXPIRED)
688 __launchpad_exec_dummy(main_fd, pool_fd, -1);
692 if (poll(pfds, POLLFD_MAX, -1) < 0)
697 WrtLogD("pfds[LAUNCH_PAD].revents : 0x%x", pfds[LAUNCH_PAD].revents) ;
698 WrtLogD("pfds[POOL_SERVER].revents : 0x%x", pfds[POOL_SERVER].revents) ;
699 WrtLogD("pfds[DUMMY_PROCESS].revents : 0x%x", pfds[DUMMY_PROCESS].revents) ;
701 /* init with concerning X & EFL (because of booting
702 * sequence problem)*/
703 if (__launchpad_post_init() < 0)
705 WrtLogE("launcpad post init failed");
709 if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0)
711 WrtLogD("pfds[LAUNCH_PAD].revents & POLLIN");
712 __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pfds[POOL_SERVER].fd);
715 if ((pfds[POOL_SERVER].revents & POLLIN) != 0)
717 int server_fd, client_fd, client_pid;
719 server_fd = pfds[POOL_SERVER].fd;
721 WrtLogD("pfds[POOL_SERVER].revents & POLLIN");
723 if (dummy_process_pid == DUMMY_NONE)
725 __accept_dummy_process(server_fd, &client_fd, &client_pid);
727 dummy_process_pid = client_pid;
728 dummy_process_fd = client_fd;
730 pfds[DUMMY_PROCESS].fd = dummy_process_fd;
731 pfds[DUMMY_PROCESS].events = POLLIN|POLLHUP;
732 pfds[DUMMY_PROCESS].revents = 0;
734 WrtLogD("Dummy process was connected! (pid:%d)", dummy_process_pid);
738 __refuse_dummy_process(server_fd);
740 WrtLogE("Refused dummy process connection!");
744 if ((pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL)) != 0)
746 WrtLogD("pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL) (pid:%d)", dummy_process_pid);
748 if (pfds[DUMMY_PROCESS].fd > -1)
750 close(pfds[DUMMY_PROCESS].fd);
753 dummy_process_pid = DUMMY_NONE;
754 dummy_process_fd = -1;
756 pfds[DUMMY_PROCESS].fd = -1;
757 pfds[DUMMY_PROCESS].events = 0;
758 pfds[DUMMY_PROCESS].revents = 0;