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>
32 #include <sys/prctl.h>
34 #include <sys/resource.h>
42 #include "menu_db_util.h"
43 #include "simple_util.h"
44 #include "access_control.h"
55 #include <app-checker.h>
58 #include "process_pool.h"
59 #include "launchpad_util.h"
61 #define _static_ static inline
62 #define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
63 #define AUL_POLL_CNT 15
64 #define AUL_PR_NAME 16
65 #define PKG_ID_LENGTH 11
67 #define EXEC_DUMMY_EXPIRED 5
68 #define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a))
69 #define WRT_CLIENT_PATH "/usr/bin/wrt-client"
70 #define LOWEST_PRIO 20
73 static char *launchpad_cmdline;
74 static int initialized = 0;
75 static int dummy_process_pid = DUMMY_NONE;
76 static int dummy_process_fd = -1;
77 static int last_dummy_exec_time = 0;
78 static int process_pool_disable = 0;
80 _static_ int __prepare_exec(const char *pkg_name,
81 const char *app_path, app_info_from_db * menu_info,
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 __dummy_launch(int dummy_client_fd, app_pkt_t* pkt);
88 _static_ int __child_raise_win_by_x(int pid, void *priv);
89 _static_ int __raise_win_by_x(int pid);
90 _static_ int __send_to_sigkill(int pid);
91 _static_ int __term_app(int pid);
92 _static_ int __resume_app(int pid);
93 _static_ void __real_send(int clifd, int ret);
94 _static_ void __send_result_to_caller(int clifd, int ret);
95 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd);
96 _static_ void __launchpad_main_loop(int main_fd, int pool_fd);
97 _static_ int __launchpad_pre_init(int argc, char **argv);
98 _static_ int __launchpad_post_init();
100 extern ail_error_e ail_db_close(void);
102 _static_ int __prepare_exec(const char *pkg_name,
103 const char *app_path, app_info_from_db * menu_info,
107 char process_name[AUL_PR_NAME];
109 /* Set new session ID & new process group ID*/
110 /* In linux, child can set new session ID without check permission */
111 /* TODO : should be add to check permission in the kernel*/
114 __preexec_run(menu_info->pkg_type, pkg_name, app_path);
120 char pkg_id[PKG_ID_LENGTH];
121 memset(pkg_id, '\0', PKG_ID_LENGTH);
122 snprintf(pkg_id, PKG_ID_LENGTH, "%s", pkg_name);
124 if (__set_access(pkg_id, menu_info->pkg_type, app_path) < 0) {
125 _D("fail to set privileges - check your package's credential\n");
129 /* SET DUMPABLE - for coredump*/
130 prctl(PR_SET_DUMPABLE, 1);
132 /* SET PROCESS NAME*/
133 if (app_path == NULL) {
134 _D("app_path should not be NULL - check menu db");
137 file_name = strrchr(app_path, '/') + 1;
138 if (file_name == NULL) {
139 _D("can't locate file name to execute");
142 memset(process_name, '\0', AUL_PR_NAME);
143 snprintf(process_name, AUL_PR_NAME, "%s", file_name);
144 prctl(PR_SET_NAME, process_name);
147 __set_env(menu_info, kb);
152 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
158 bundle_encode(kb, &kb_data, &datalen);
159 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
160 _E("error request fake launch - error code = %d", ret);
166 _static_ int __normal_fork_exec(int argc, char **argv)
168 _D("start real fork and exec\n");
170 // warning: unused parameter
173 if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
174 if (errno == EACCES) {
175 _E("such a file is no executable - %s", argv[0]);
177 _E("unknown executable error - %s", argv[0]);
185 _static_ void __real_launch(const char *app_path, bundle * kb)
191 app_argv = __create_argc_argv(kb, &app_argc);
193 #ifndef NATIVE_LAUNCHPAD
194 if (__change_cmdline((char *)app_path) < 0) {
195 _E("change cmdline fail");
199 app_argv[0] = g_argv[0];
201 app_argv[0] = strdup(app_path);
204 for (i = 0; i < app_argc; i++) {
205 _D("input argument %d : %s##", i, app_argv[i]);
208 PERF("setup argument done");
209 _E("lock up test log(no error) : setup argument done");
211 /* Temporary log: launch time checking */
212 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
214 __preload_exec(app_argc, app_argv);
216 __normal_fork_exec(app_argc, app_argv);
219 _static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt)
221 return __send_pkt_raw_data(dummy_client_fd, pkt);
224 _static_ int __child_raise_win_by_x(int pid, void *priv)
226 // warning: unused parameter
229 return x_util_raise_win(pid);
232 _static_ int __raise_win_by_x(int pid)
235 if (x_util_raise_win(pid) == 0) {
239 /* support app launched by shell script*/
241 _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
247 if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0) {
254 _static_ int __send_to_sigkill(int pid)
263 if (killpg(pgid, SIGKILL) < 0) {
270 _static_ int __term_app(int pid)
274 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0)
276 _D("terminate packet send error - use SIGKILL");
277 if (__send_to_sigkill(pid) < 0) {
278 _E("fail to killing - %d\n", pid);
286 _static_ int __resume_app(int pid)
291 __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
294 if (ret == -EAGAIN) {
295 _E("resume packet timeout error");
297 _D("resume packet send error - use raise win");
298 if (__raise_win_by_x(pid) < 0) {
299 _E("raise failed - %d resume fail\n", pid);
300 _E("we will term the app - %d\n", pid);
301 __send_to_sigkill(pid);
312 static int __get_caller_pid(bundle *kb)
317 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
322 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
323 if (pid_str == NULL) {
336 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
339 char tmp_pid[MAX_PID_STR_BUFSZ];
344 if ((pid = __get_caller_pid(kb)) < 0) {
348 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
350 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
352 bundle_encode(kb, &kb_data, &datalen);
353 if ((res = __app_send_raw(pid, cmd, kb_data, datalen)) < 0) {
362 _static_ void __real_send(int clifd, int ret)
364 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
365 if (errno == EPIPE) {
366 _E("send failed due to EPIPE.\n");
368 _E("send fail to client");
374 _static_ void __send_result_to_caller(int clifd, int ret)
378 int cmdline_changed = 0;
379 int cmdline_exist = 0;
386 __real_send(clifd, ret);
389 /* check normally was launched?*/
392 cmdline = __proc_get_cmdline_bypid(ret);
393 if (cmdline == NULL) {
394 _E("error founded when being launched with %d", ret);
395 } else if (strcmp(cmdline, launchpad_cmdline)) {
404 _D("-- now wait to change cmdline --");
405 struct timespec duration = { 0, 50 * 1000 * 1000 };
406 nanosleep(&duration, NULL); /* 50ms sleep*/
408 } while (wait_count <= 20); /* max 50*20ms will be sleep*/
410 if ((!cmdline_exist) && (!cmdline_changed)) {
411 __real_send(clifd, -1); /* abnormally launched*/
415 if (!cmdline_changed) {
416 _E("process launched, but cmdline not changed");
419 __real_send(clifd, ret);
423 _static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd)
427 last_dummy_exec_time = time(NULL);
431 if (pid == 0) // child
433 setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
434 _D("Launch dummy process...");
436 //temp - this requires some optimization.
438 _D("sleeping 1sec...");
440 /* Set new session ID & new process group ID*/
441 /* In linux, child can set new session ID without check permission */
442 /* TODO : should be add to check permission in the kernel*/
464 __signal_unset_sigchld();
467 /* SET DUMPABLE - for coredump*/
468 prctl(PR_SET_DUMPABLE, 1);
472 int (*dl_main) (int, char **);
474 handle = dlopen(WRT_CLIENT_PATH, RTLD_NOW | RTLD_GLOBAL);
478 _E("dlopen failed.");
482 dl_main = dlsym(handle, "main");
484 sprintf(g_argv[1], "%s", "-d");
488 dl_main(g_argc, g_argv);
492 _E("dlsym not founded. bad preloaded app - check fpie pie");
500 _static_ void __launchpad_main_loop(int main_fd, int pool_fd)
503 app_pkt_t *pkt = NULL;
504 app_info_from_db *menu_info = NULL;
506 const char *pkg_name = NULL;
507 const char *app_path = NULL;
511 int is_real_launch = 0;
513 char sock_path[UNIX_PATH_MAX] = { 0, };
515 pkt = __app_recv_raw(main_fd, &clifd, &cr);
517 _D("packet is NULL");
521 kb = bundle_decode(pkt->data, pkt->len);
523 _D("bundle decode error");
528 PERF("packet processing start");
530 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
531 _D("pkg name : %s\n", pkg_name);
533 menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
534 if (menu_info == NULL) {
535 _D("such pkg no found");
539 app_path = _get_app_path(menu_info);
540 if (app_path == NULL) {
541 _E("app_path is NULL");
544 if (app_path[0] != '/') {
545 _D("app_path is not absolute path");
549 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
550 pkg_name = _get_pkgname(menu_info);
552 PERF("get package information & modify bundle done");
554 if (dummy_process_pid != DUMMY_NONE)
556 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, dummy_process_pid);
559 __dummy_launch(dummy_process_fd, pkt);
561 pid = dummy_process_pid;
563 close(dummy_process_fd);
565 dummy_process_pid = DUMMY_NONE;
566 dummy_process_fd = -1;
568 /* Temporary log: launch time checking */
569 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
571 __launchpad_exec_dummy(main_fd, pool_fd, clifd);
573 _D("==> dummy launch pid : %d %s\n", pid, app_path);
582 _E("lock up test log(no error) : fork done");
586 __signal_unset_sigchld();
589 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
592 PERF("prepare exec - first done");
593 _E("lock up test log(no error) : prepare exec - first done");
595 if (__prepare_exec(pkg_name, app_path,
598 _E("preparing work fail to launch - "
599 "can not launch %s\n", pkg_name);
603 PERF("prepare exec - second done");
604 _E("lock up test log(no error) : prepare exec - second done");
606 __real_launch(app_path, kb);
610 _D("==> real launch pid : %d %s\n", pid, app_path);
615 __send_result_to_caller(clifd, pid);
618 if (is_real_launch) {
620 __signal_block_sigchld();
621 __send_app_launch_signal(pid);
622 __signal_unblock_sigchld();
626 if (menu_info != NULL) {
627 _free_app_info_from_db(menu_info);
637 /* Active Flusing for Daemon */
638 if (initialized > AUL_POLL_CNT) {
639 sqlite3_release_memory(SQLITE_FLUSH_MAX);
645 _static_ int __launchpad_pre_init(int argc, char **argv)
652 /* get my(launchpad) command line*/
653 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
654 if (launchpad_cmdline == NULL) {
655 _E("launchpad cmdline fail to get");
658 _D("launchpad cmdline = %s", launchpad_cmdline);
660 /* create launchpad sock */
661 fd = __create_server_sock(WRT_LAUNCHPAD_PID);
663 _E("server sock error");
667 __preload_init(argc, argv);
669 __preload_init_for_wrt();
671 __preexec_init(argc, argv);
676 _static_ int __launchpad_post_init()
678 /* Setting this as a global variable to keep track
679 * of launchpad poll cnt */
680 /* static int initialized = 0;*/
687 if (__signal_set_sigchld() < 0) {
696 int main(int argc, char **argv)
705 int main_fd = -1, pool_fd = -1;
706 struct pollfd pfds[POLLFD_MAX];
708 memset(pfds, 0x00, sizeof(pfds));
710 // process pool feature disable
711 if (getenv("WRT_PROCESS_POOL_DISABLE"))
713 process_pool_disable = 1;
716 /* init without concerning X & EFL*/
717 main_fd = __launchpad_pre_init(argc, argv);
721 _E("launchpad pre init failed");
725 pfds[LAUNCH_PAD].fd = main_fd;
726 pfds[LAUNCH_PAD].events = POLLIN;
727 pfds[LAUNCH_PAD].revents = 0;
729 pool_fd = __create_process_pool_server();
733 _E("Error creationg pool server!");
737 pfds[POOL_SERVER].fd = pool_fd;
738 pfds[POOL_SERVER].events = POLLIN;
739 pfds[POOL_SERVER].revents = 0;
743 if (dummy_process_pid == DUMMY_NONE)
745 pfds[DUMMY_PROCESS].fd = -1;
746 pfds[DUMMY_PROCESS].events = 0;
747 pfds[DUMMY_PROCESS].revents = 0;
749 if ( !process_pool_disable &&
750 DIFF(last_dummy_exec_time, time(NULL)) > EXEC_DUMMY_EXPIRED)
752 __launchpad_exec_dummy(main_fd, pool_fd, -1);
756 if (poll(pfds, POLLFD_MAX, -1) < 0)
761 _D("pfds[LAUNCH_PAD].revents : 0x%x", pfds[LAUNCH_PAD].revents) ;
762 _D("pfds[POOL_SERVER].revents : 0x%x", pfds[POOL_SERVER].revents) ;
763 _D("pfds[DUMMY_PROCESS].revents : 0x%x", pfds[DUMMY_PROCESS].revents) ;
765 /* init with concerning X & EFL (because of booting
766 * sequence problem)*/
767 if (__launchpad_post_init() < 0)
769 _E("launcpad post init failed");
773 if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0)
775 _D("pfds[LAUNCH_PAD].revents & POLLIN");
776 __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pfds[POOL_SERVER].fd);
779 if ((pfds[POOL_SERVER].revents & POLLIN) != 0)
781 int server_fd, client_fd, client_pid;
783 server_fd = pfds[POOL_SERVER].fd;
785 _D("pfds[POOL_SERVER].revents & POLLIN");
787 if (dummy_process_pid == DUMMY_NONE)
789 __accept_dummy_process(server_fd, &client_fd, &client_pid);
791 dummy_process_pid = client_pid;
792 dummy_process_fd = client_fd;
794 pfds[DUMMY_PROCESS].fd = dummy_process_fd;
795 pfds[DUMMY_PROCESS].events = POLLIN|POLLHUP;
796 pfds[DUMMY_PROCESS].revents = 0;
798 _D("Dummy process was connected! (pid:%d)", dummy_process_pid);
802 __refuse_dummy_process(server_fd);
804 _E("Refused dummy process connection!");
808 if ((pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL)) != 0)
810 _D("pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL) (pid:%d)", dummy_process_pid);
811 close(pfds[DUMMY_PROCESS].fd);
813 dummy_process_pid = DUMMY_NONE;
814 dummy_process_fd = -1;
816 pfds[DUMMY_PROCESS].fd = -1;
817 pfds[DUMMY_PROCESS].events = 0;
818 pfds[DUMMY_PROCESS].revents = 0;