4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>, Jaeho Lee <jaeho81.lee@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
24 * simple AUL daemon - launchpad
31 #include <sys/types.h>
38 #include <sys/prctl.h>
46 #include "menu_db_util.h"
47 #include "simple_util.h"
48 #include "access_control.h"
61 #define _static_ static inline
63 #define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
64 #define AUL_POLL_CNT 15
65 #define AUL_PR_NAME 16
66 #define PATH_TMP "/tmp"
67 #define PATH_DATA "/data"
69 #define SDK_CODE_COVERAGE "CODE_COVERAGE"
70 #define SDK_DEBUG "DEBUG"
71 #define SDK_DYNAMIC_ANALYSIS "DYNAMIC_ANALYSIS"
72 #define SDK_UNIT_TEST "UNIT_TEST"
74 /* DLP is short for debug-launchpad */
75 #define DLP_K_DEBUG_ARG "__DLP_DEBUG_ARG__"
76 #define DLP_K_UNIT_TEST_ARG "__DLP_UNIT_TEST_ARG__"
78 #define PATH_GDBSERVER "/home/developer/sdk_tools/gdbserver/gdbserver"
79 #define PATH_DA_SO "/usr/lib/da_probe_osp.so"
82 static char *launchpad_cmdline;
83 static int initialized = 0;
86 _static_ void __set_oom();
87 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb);
88 _static_ int __prepare_exec(const char *pkg_name,
89 const char *app_path, app_info_from_db * menu_info,
91 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
92 _static_ char **__create_argc_argv(bundle * kb, int *margc, const char *app_path);
93 _static_ int __normal_fork_exec(int argc, char **argv);
94 _static_ void __real_launch(const char *app_path, bundle * kb);
95 static inline int __parser(const char *arg, char *out, int out_size);
96 _static_ void __modify_bundle(bundle * kb, int caller_pid,
97 app_info_from_db * menu_info, int cmd);
98 _static_ int __child_raise_win_by_x(int pid, void *priv);
99 _static_ int __raise_win_by_x(int pid);
100 _static_ int __send_to_sigkill(int pid);
101 _static_ int __term_app(int pid);
102 _static_ int __resume_app(int pid);
103 _static_ void __real_send(int clifd, int ret);
104 _static_ void __send_result_to_caller(int clifd, int ret);
105 _static_ void __launchpad_main_loop(int main_fd);
106 _static_ int __launchpad_pre_init(int argc, char **argv);
107 _static_ int __launchpad_post_init();
109 extern ail_error_e ail_db_close(void);
113 _static_ void __set_oom()
115 char buf[MAX_LOCAL_BUFSZ];
118 /* we should reset oomadj value as default because child
119 inherits from parent oom_adj*/
120 snprintf(buf, MAX_LOCAL_BUFSZ, "/proc/%d/oom_adj", getpid());
121 fp = fopen(buf, "w");
124 fprintf(fp, "%d", -16);
128 _static_ void __set_sdk_env(app_info_from_db* menu_info, char* str) {
129 char buf_pkgname[MAX_LOCAL_BUFSZ];
130 char buf[MAX_LOCAL_BUFSZ];
133 _D("key : %s / value : %s", AUL_K_SDK, str);
134 /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
135 /* GCOV_PREFIX contains the prefix to add to the absolute paths in the object file. */
136 /* Prefix can be absolute, or relative. The default is no prefix. */
137 /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
138 /* to stripoff the hardwired absolute paths. Default value is 0. */
139 if (strncmp(str, SDK_CODE_COVERAGE, strlen(str)) == 0) {
140 strncpy(buf_pkgname,_get_pkgname(menu_info),MAX_LOCAL_BUFSZ);
141 snprintf(buf, MAX_LOCAL_BUFSZ, PATH_TMP"/%s"PATH_DATA, strtok(buf_pkgname,"."));
142 ret = setenv("GCOV_PREFIX", buf, 1);
143 _D("GCOV_PREFIX : %d", ret);
144 ret = setenv("GCOV_PREFIX_STRIP", "0", 1);
145 _D("GCOV_PREFIX_STRIP : %d", ret);
146 } else if (strncmp(str, SDK_DYNAMIC_ANALYSIS, strlen(str)) == 0) {
147 ret = setenv("LD_PRELOAD", PATH_DA_SO, 1);
148 _D("LD_PRELOAD : %d", ret);
153 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
156 const char **str_array;
160 setenv("PKG_NAME", _get_pkgname(menu_info), 1);
164 str = bundle_get_val(kb, AUL_K_STARTTIME);
166 setenv("APP_START_TIME", str, 1);
168 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
169 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
170 if(str_array != NULL) {
171 for (i = 0; i < len; i++) {
172 _D("index : [%d]", i);
173 __set_sdk_env(menu_info, (char *)str_array[i]);
177 str = bundle_get_val(kb, AUL_K_SDK);
179 __set_sdk_env(menu_info, (char *)str);
182 if (menu_info->hwacc != NULL)
183 setenv("HWACC", menu_info->hwacc, 1);
186 _static_ int __prepare_exec(const char *pkg_name,
187 const char *app_path, app_info_from_db * menu_info,
191 char process_name[AUL_PR_NAME];
194 /* Set new session ID & new process group ID*/
195 /* In linux, child can set new session ID without check permission */
196 /* TODO : should be add to check permission in the kernel*/
199 __preexec_run(menu_info->pkg_type, pkg_name, app_path);
205 if(bundle_get_val(kb, AUL_K_PRIVACY_APPID) == NULL) {
206 _D("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path);
207 if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) {
208 _D("fail to set privileges - check your package's credential : %d\n", ret);
212 /* SET DUMPABLE - for coredump*/
213 prctl(PR_SET_DUMPABLE, 1);
215 /* SET PROCESS NAME*/
216 if (app_path == NULL) {
217 _D("app_path should not be NULL - check menu db");
220 file_name = strrchr(app_path, '/') + 1;
221 if (file_name == NULL) {
222 _D("can't locate file name to execute");
225 memset(process_name, '\0', AUL_PR_NAME);
226 snprintf(process_name, AUL_PR_NAME, "%s", file_name);
227 prctl(PR_SET_NAME, process_name);
230 __set_env(menu_info, kb);
235 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
241 bundle_encode(kb, &kb_data, &datalen);
242 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
243 _E("error request fake launch - error code = %d", ret);
248 _static_ char **__add_arg(bundle * kb, char **argv, int *margc, const char *key)
250 const char *str = NULL;
251 const char **str_array = NULL;
255 if(bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
256 str_array = bundle_get_str_array(kb, key, &len);
258 str = bundle_get_val(kb, key);
264 if(str_array != NULL) {
265 if(strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0) {
266 argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+2));
267 if(!argv) _E("realloc fail");
268 for(i=*margc+len+1; i-(len+1)>=0; i--) {
269 argv[i] = argv[i-(len+1)];
271 argv[0] = strdup(PATH_GDBSERVER);
272 for(i=0; i<len; i++) {
273 argv[1+i] = strdup(str_array[i]);
275 len++; /* gdbserver */
277 argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+1));
278 if(!argv) _E("realloc fail");
279 for(i=0; i<len; i++) {
280 argv[*margc+i] = strdup(str_array[i]);
283 argv[*margc+len] = NULL;
290 _static_ char **__create_argc_argv(bundle * kb, int *margc, const char *app_path)
295 const char *str = NULL;
296 const char **str_array = NULL;
300 argc = bundle_export_to_argv(kb, &argv);
301 argv[0] = strdup(app_path);
303 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
304 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
306 str = bundle_get_val(kb, AUL_K_SDK);
312 if(str_array != NULL) {
313 for (i = 0; i < len; i++) {
314 if(str_array[i] == NULL) break;
315 _D("index : [%d]", i);
316 if (strncmp(str_array[i], SDK_DEBUG, strlen(str_array[i])) == 0) {
317 argv = __add_arg(kb, argv, &argc, DLP_K_DEBUG_ARG);
318 } else if (strncmp(str_array[i], SDK_UNIT_TEST, strlen(str_array[i])) == 0) {
319 argv = __add_arg(kb, argv, &argc, DLP_K_UNIT_TEST_ARG);
328 _static_ int __normal_fork_exec(int argc, char **argv)
330 _D("start real fork and exec\n");
332 if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
334 _E("such a file is no executable - %s", argv[0]);
336 _E("unknown executable error - %s", argv[0]);
343 _static_ void __real_launch(const char *app_path, bundle * kb)
349 app_argv = __create_argc_argv(kb, &app_argc, app_path);
351 for (i = 0; i < app_argc; i++)
352 _D("input argument %d : %s##", i, app_argv[i]);
354 PERF("setup argument done");
355 _D("lock up test log(no error) : setup argument done");
357 /* Temporary log: launch time checking */
358 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
360 __normal_fork_exec(app_argc, app_argv);
365 * Parsing original app path to retrieve default bundle
367 * -1 : Invalid sequence
368 * -2 : Buffer overflow
371 static inline int __parser(const char *arg, char *out, int out_size)
375 char *start_out = out;
377 if (arg == NULL || out == NULL) {
378 /* Handles null buffer*/
382 for (i = 0; out_size > 1; i++) {
406 case 2: /* escape start*/
421 case 4: /* character escape*/
422 if (arg[i] == '\0') {
432 if (out != start_out) {
441 return -1; /* error*/
442 case 7: /* terminate*/
459 _static_ void __modify_bundle(bundle * kb, int caller_pid,
460 app_info_from_db * menu_info, int cmd)
462 bundle_del(kb, AUL_K_PKG_NAME);
463 bundle_del(kb, AUL_K_EXEC);
464 bundle_del(kb, AUL_K_PACKAGETYPE);
465 bundle_del(kb, AUL_K_HWACC);
467 /* Parse app_path to retrieve default bundle*/
468 if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_OPEN || cmd == APP_RESUME) {
470 char exe[MAX_PATH_LEN];
473 ptr = _get_original_app_path(menu_info);
475 flag = __parser(ptr, exe, sizeof(exe));
481 _D("parsing app_path: EXEC - %s\n", exe);
484 flag = __parser(ptr, key, sizeof(key));
489 flag = __parser(ptr, value, sizeof(value));
494 /*bundle_del(kb, key);*/
495 bundle_add(kb, key, value);
497 } else if (flag == 0) {
498 _D("parsing app_path: No arguments\n");
500 _D("parsing app_path: Invalid argument\n");
505 _static_ int __child_raise_win_by_x(int pid, void *priv)
507 return x_util_raise_win(pid);
510 _static_ int __raise_win_by_x(int pid)
513 if (x_util_raise_win(pid) == 0)
516 /* support app launched by shell script*/
518 _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
523 if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0)
529 _static_ int __send_to_sigkill(int pid)
537 if (killpg(pgid, SIGKILL) < 0)
543 _static_ int __term_app(int pid)
547 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
548 _D("terminate packet send error - use SIGKILL");
549 if (__send_to_sigkill(pid) < 0) {
550 _E("fail to killing - %d\n", pid);
558 _static_ int __resume_app(int pid)
563 __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
566 _E("resume packet timeout error");
568 _D("resume packet send error - use raise win");
569 if (__raise_win_by_x(pid) < 0) {
570 _E("raise failed - %d resume fail\n", pid);
571 _E("we will term the app - %d\n", pid);
572 __send_to_sigkill(pid);
582 static int __get_caller_pid(bundle *kb)
587 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
591 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
603 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
606 char tmp_pid[MAX_PID_STR_BUFSZ];
611 if ((pid = __get_caller_pid(kb)) < 0)
614 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
616 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
618 bundle_encode(kb, &kb_data, &datalen);
619 if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0)
627 _static_ void __real_send(int clifd, int ret)
629 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
630 if (errno == EPIPE) {
631 _E("send failed due to EPIPE.\n");
633 _E("send fail to client");
639 _static_ void __send_result_to_caller(int clifd, int ret)
643 int cmdline_changed = 0;
644 int cmdline_exist = 0;
650 __real_send(clifd, ret);
653 /* check normally was launched?*/
656 cmdline = __proc_get_cmdline_bypid(ret);
657 if (cmdline == NULL) {
658 _E("error founded when being launched with %d", ret);
660 } else if (strcmp(cmdline, launchpad_cmdline)) {
669 _D("-- now wait to change cmdline --");
670 usleep(50 * 1000); /* 50ms sleep*/
672 } while (wait_count <= 20); /* max 50*20ms will be sleep*/
674 if ((!cmdline_exist) && (!cmdline_changed)) {
675 __real_send(clifd, -1); /* abnormally launched*/
679 if (!cmdline_changed)
680 _E("process launched, but cmdline not changed");
682 __real_send(clifd, ret);
686 static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
687 const char *pkgname, bundle *kb)
689 app_info_from_db *menu_info;
691 menu_info = calloc(1, sizeof(app_info_from_db));
692 if (menu_info == NULL) {
696 menu_info->pkg_name = strdup(pkgname);
697 menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC));
698 if (menu_info->app_path != NULL)
699 menu_info->original_app_path = strdup(menu_info->app_path);
700 menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE));
701 menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC));
703 if (!_get_app_path(menu_info)) {
704 _free_app_info_from_db(menu_info);
711 _static_ void __launchpad_main_loop(int main_fd)
714 app_pkt_t *pkt = NULL;
715 app_info_from_db *menu_info = NULL;
717 const char *pkg_name = NULL;
718 const char *app_path = NULL;
722 int is_real_launch = 0;
724 char sock_path[UNIX_PATH_MAX] = {0,};
726 pkt = __app_recv_raw(main_fd, &clifd, &cr);
728 _D("packet is NULL");
732 kb = bundle_decode(pkt->data, pkt->len);
734 _D("bundle decode error");
739 PERF("packet processing start");
741 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
742 _D("pkg name : %s\n", pkg_name);
744 menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
745 if (menu_info == NULL) {
746 _D("such pkg no found");
750 app_path = _get_app_path(menu_info);
751 if(app_path == NULL) {
752 _E("app_path is NULL");
755 if (app_path[0] != '/') {
756 _D("app_path is not absolute path");
760 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
761 pkg_name = _get_pkgname(menu_info);
763 PERF("get package information & modify bundle done");
769 _D("lock up test log(no error) : fork done");
773 __signal_unset_sigchld();
776 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
779 PERF("prepare exec - first done");
780 _D("lock up test log(no error) : prepare exec - first done");
782 if (__prepare_exec(pkg_name, app_path,
783 menu_info, kb) < 0) {
784 _E("preparing work fail to launch - "
785 "can not launch %s\n", pkg_name);
789 PERF("prepare exec - second done");
790 _D("lock up test log(no error) : prepare exec - second done");
792 __real_launch(app_path, kb);
796 _D("==> real launch pid : %d %s\n", pid, app_path);
801 __send_result_to_caller(clifd, pid);
804 if (is_real_launch) {
806 __signal_block_sigchld();
807 __send_app_launch_signal(pid);
808 __signal_unblock_sigchld();
812 if (menu_info != NULL)
813 _free_app_info_from_db(menu_info);
820 /* Active Flusing for Daemon */
821 if (initialized > AUL_POLL_CNT) {
822 sqlite3_release_memory(SQLITE_FLUSH_MAX);
829 _static_ int __launchpad_pre_init(int argc, char **argv)
836 /* get my(launchpad) command line*/
837 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
838 if (launchpad_cmdline == NULL) {
839 _E("launchpad cmdline fail to get");
842 _D("launchpad cmdline = %s", launchpad_cmdline);
844 /* create launchpad sock */
845 fd = __create_server_sock(DEBUG_LAUNCHPAD_PID);
847 _E("server sock error");
851 __preload_init(argc, argv);
853 __preexec_init(argc, argv);
858 _static_ int __launchpad_post_init()
860 /* Setting this as a global variable to keep track
861 of launchpad poll cnt */
862 /* static int initialized = 0;*/
869 if (__signal_set_sigchld() < 0)
877 int main(int argc, char **argv)
880 struct pollfd pfds[POLLFD_MAX];
883 /* init without concerning X & EFL*/
884 main_fd = __launchpad_pre_init(argc, argv);
886 _E("launchpad pre init failed");
890 pfds[0].fd = main_fd;
891 pfds[0].events = POLLIN;
895 if (poll(pfds, POLLFD_MAX, -1) < 0)
898 /* init with concerning X & EFL (because of booting
900 if (__launchpad_post_init() < 0) {
901 _E("launcpad post init failed");
905 for (i = 0; i < POLLFD_MAX; i++) {
906 if ((pfds[i].revents & POLLIN) != 0) {
907 __launchpad_main_loop(pfds[i].fd);