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"
60 #include <app-checker.h>
63 #define _static_ static inline
65 #define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
66 #define AUL_POLL_CNT 15
67 #define AUL_PR_NAME 16
68 #define PATH_APP_ROOT "/opt/apps"
69 #define PATH_DATA "/data"
70 #define SDK_CODE_COVERAGE "CODE_COVERAGE"
71 #define SDK_DYNAMIC_ANALYSIS "DYNAMIC_ANALYSIS"
72 #define PATH_DA_SO "/home/developer/sdk_tools/da/da_probe.so"
75 static char *launchpad_cmdline;
76 static int initialized = 0;
79 _static_ void __set_oom();
80 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb);
81 _static_ int __prepare_exec(const char *pkg_name,
82 const char *app_path, app_info_from_db * menu_info,
84 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
85 _static_ char **__create_argc_argv(bundle * kb, int *margc);
86 _static_ int __normal_fork_exec(int argc, char **argv);
87 _static_ void __real_launch(const char *app_path, bundle * kb);
88 _static_ void __add_history(int caller, int callee, const char *pkgname,
89 bundle *b, const char *app_path);
90 static inline int __parser(const char *arg, char *out, int out_size);
91 _static_ void __modify_bundle(bundle * kb, int caller_pid,
92 app_info_from_db * menu_info, int cmd);
93 _static_ int __child_raise_win_by_x(int pid, void *priv);
94 _static_ int __raise_win_by_x(int pid);
95 _static_ int __send_to_sigkill(int pid);
96 _static_ int __term_app(int pid);
97 _static_ int __resume_app(int pid);
98 _static_ int __app_process_by_pid(int cmd,
99 const char *pkg_name, struct ucred *cr);
100 _static_ int __nofork_processing(int cmd, int pid, bundle * kb);
101 _static_ void __real_send(int clifd, int ret);
102 _static_ void __send_result_to_caller(int clifd, int ret);
103 _static_ void __launchpad_main_loop(int main_fd);
104 _static_ int __launchpad_pre_init(int argc, char **argv);
105 _static_ int __launchpad_post_init();
107 extern ail_error_e ail_db_close(void);
111 _static_ void __set_oom()
113 char buf[MAX_LOCAL_BUFSZ];
116 /* we should reset oomadj value as default because child
117 inherits from parent oom_adj*/
118 snprintf(buf, MAX_LOCAL_BUFSZ, "/proc/%d/oom_adj", getpid());
119 fp = fopen(buf, "w");
122 fprintf(fp, "%d", -16);
126 _static_ void __set_sdk_env(app_info_from_db* menu_info, char* str) {
127 char buf[MAX_LOCAL_BUFSZ];
130 _D("key : %s / value : %s", AUL_K_SDK, str);
131 /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
132 /* GCOV_PREFIX contains the prefix to add to the absolute paths in the object file. */
133 /* Prefix can be absolute, or relative. The default is no prefix. */
134 /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
135 /* to stripoff the hardwired absolute paths. Default value is 0. */
136 if (strncmp(str, SDK_CODE_COVERAGE, strlen(str)) == 0) {
137 snprintf(buf, MAX_LOCAL_BUFSZ, PATH_APP_ROOT"/%s"PATH_DATA, _get_pkgname(menu_info));
138 ret = setenv("GCOV_PREFIX", buf, 1);
139 _D("GCOV_PREFIX : %d", ret);
140 ret = setenv("GCOV_PREFIX_STRIP", "4096", 1);
141 _D("GCOV_PREFIX_STRIP : %d", ret);
142 } else if (strncmp(str, SDK_DYNAMIC_ANALYSIS, strlen(str)) == 0) {
143 ret = setenv("LD_PRELOAD", PATH_DA_SO, 1);
144 _D("LD_PRELOAD : %d", ret);
149 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
152 const char **str_array;
156 setenv("PKG_NAME", _get_pkgname(menu_info), 1);
160 str = bundle_get_val(kb, AUL_K_STARTTIME);
162 setenv("APP_START_TIME", str, 1);
164 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
165 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
166 if(str_array != NULL) {
167 for (i = 0; i < len; i++) {
168 _D("index : [%d]", i);
169 __set_sdk_env(menu_info, (char *)str_array[i]);
173 str = bundle_get_val(kb, AUL_K_SDK);
175 __set_sdk_env(menu_info, (char *)str);
180 _static_ int __prepare_exec(const char *pkg_name,
181 const char *app_path, app_info_from_db * menu_info,
185 char process_name[AUL_PR_NAME];
187 /* Set new session ID & new process group ID*/
188 /* In linux, child can set new session ID without check permission */
189 /* TODO : should be add to check permission in the kernel*/
195 /* SET SMACK LABEL */
196 __set_smack((char *)app_path);
199 if (__set_dac(pkg_name) < 0) {
200 _D("fail to set DAC - check your package's credential\n");
203 /* SET DUMPABLE - for coredump*/
204 prctl(PR_SET_DUMPABLE, 1);
206 /* SET PROCESS NAME*/
207 if (app_path == NULL) {
208 _D("app_path should not be NULL - check menu db");
211 file_name = strrchr(app_path, '/') + 1;
212 if (file_name == NULL) {
213 _D("can't locate file name to execute");
216 memset(process_name, '\0', AUL_PR_NAME);
217 snprintf(process_name, AUL_PR_NAME, "%s", file_name);
218 prctl(PR_SET_NAME, process_name);
221 __set_env(menu_info, kb);
226 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
232 bundle_encode(kb, &kb_data, &datalen);
233 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
234 _E("error request fake launch - error code = %d", ret);
239 _static_ char **__create_argc_argv(bundle * kb, int *margc)
244 argc = bundle_export_to_argv(kb, &argv);
250 _static_ int __normal_fork_exec(int argc, char **argv)
252 _D("start real fork and exec\n");
254 if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
256 _E("such a file is no executable - %s", argv[0]);
258 _E("unknown executable error - %s", argv[0]);
265 _static_ void __real_launch(const char *app_path, bundle * kb)
271 app_argv = __create_argc_argv(kb, &app_argc);
272 app_argv[0] = strdup(app_path);
274 for (i = 0; i < app_argc; i++)
275 _D("input argument %d : %s##", i, app_argv[i]);
277 PERF("setup argument done");
278 _E("lock up test log(no error) : setup argument done");
280 /* Temporary log: launch time checking */
281 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
283 __preload_exec(app_argc, app_argv);
285 __normal_fork_exec(app_argc, app_argv);
288 _static_ void __add_history(int caller, int callee, const char *pkgname,
289 bundle *b, const char *app_path)
291 struct history_data *hd;
295 _D("***** HISTORY *****\n");
296 _D("%d ==> %d(%s) \n", caller, callee, pkgname);
297 _D("*******************\n");
300 bundle_encode(b, (bundle_raw **)&kb_data, &len);
301 hd = (struct history_data *)malloc(sizeof(char) * (len+1029));
303 strncpy(hd->pkg_name, pkgname, MAX_PACKAGE_STR_SIZE-1);
304 strncpy(hd->app_path, app_path, MAX_PACKAGE_APP_PATH_SIZE-1);
306 memcpy(hd->data, kb_data, len);
308 __app_send_raw(AUL_UTIL_PID, ADD_HISTORY, (unsigned char *)hd,
313 hd = (struct history_data *)malloc(sizeof(char) * 1029);
315 strncpy(hd->pkg_name, pkgname, MAX_PACKAGE_STR_SIZE-1);
316 strncpy(hd->app_path, app_path, MAX_PACKAGE_APP_PATH_SIZE-1);
319 __app_send_raw(AUL_UTIL_PID, ADD_HISTORY, (unsigned char *)hd,
329 * Parsing original app path to retrieve default bundle
331 * -1 : Invalid sequence
332 * -2 : Buffer overflow
335 static inline int __parser(const char *arg, char *out, int out_size)
339 char *start_out = out;
341 if (arg == NULL || out == NULL) {
342 /* Handles null buffer*/
346 for (i = 0; out_size > 1; i++) {
370 case 2: /* escape start*/
385 case 4: /* character escape*/
386 if (arg[i] == '\0') {
396 if (out != start_out) {
405 return -1; /* error*/
406 case 7: /* terminate*/
423 _static_ void __modify_bundle(bundle * kb, int caller_pid,
424 app_info_from_db * menu_info, int cmd)
426 char tmp_pid[MAX_PID_STR_BUFSZ];
428 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", caller_pid);
429 bundle_add(kb, AUL_K_CALLER_PID, tmp_pid);
430 bundle_del(kb, AUL_K_PKG_NAME);
431 if (cmd == APP_START_RES)
432 bundle_add(kb, AUL_K_WAIT_RESULT, "1");
434 /* Parse app_path to retrieve default bundle*/
435 if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_RESUME) {
437 char exe[MAX_PATH_LEN];
440 ptr = _get_original_app_path(menu_info);
442 flag = __parser(ptr, exe, sizeof(exe));
448 _D("parsing app_path: EXEC - %s\n", exe);
451 flag = __parser(ptr, key, sizeof(key));
456 flag = __parser(ptr, value, sizeof(value));
461 /*bundle_del(kb, key);*/
462 bundle_add(kb, key, value);
464 } else if (flag == 0) {
465 _D("parsing app_path: No arguments\n");
467 _D("parsing app_path: Invalid argument\n");
472 _static_ int __child_raise_win_by_x(int pid, void *priv)
474 return x_util_raise_win(pid);
477 _static_ int __raise_win_by_x(int pid)
480 if (x_util_raise_win(pid) == 0)
483 /* support app launched by shell script*/
485 _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
490 if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0)
496 _static_ int __send_to_sigkill(int pid)
504 if (killpg(pgid, SIGKILL) < 0)
510 _static_ int __term_app(int pid)
514 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
515 _D("terminate packet send error - use SIGKILL");
516 if (__send_to_sigkill(pid) < 0) {
517 _E("fail to killing - %d\n", pid);
525 _static_ int __resume_app(int pid)
530 __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
533 _E("resume packet timeout error");
535 _D("resume packet send error - use raise win");
536 if (__raise_win_by_x(pid) < 0) {
537 _E("raise failed - %d resume fail\n", pid);
538 _E("we will term the app - %d\n", pid);
539 __send_to_sigkill(pid);
549 static int __get_caller_pid(bundle *kb)
554 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
558 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
570 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
573 char tmp_pid[MAX_PID_STR_BUFSZ];
578 if ((pid = __get_caller_pid(kb)) < 0)
581 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
583 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
585 bundle_encode(kb, &kb_data, &datalen);
586 if ((res = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
594 _static_ int __app_process_by_pid(int cmd,
595 const char *pkg_name, struct ucred *cr)
600 if (pkg_name == NULL)
603 if ((cr->uid != 0) && (cr->uid != INHOUSE_UID)) {
604 _E("reject by security rule, your uid is %u\n", cr->uid);
608 pid = atoi(pkg_name);
615 case APP_RESUME_BY_PID:
616 ret = __resume_app(pid);
618 case APP_TERM_BY_PID:
619 ret = __term_app(pid);
621 case APP_KILL_BY_PID:
622 if ((ret = __send_to_sigkill(pid)) < 0)
623 _E("fail to killing - %d\n", pid);
629 _static_ int __nofork_processing(int cmd, int pid, bundle * kb)
634 _D("resume app's pid : %d\n", pid);
635 if ((ret = __resume_app(pid)) < 0)
636 _E("__resume_app failed. error code = %d", ret);
637 PERF("resume app done");
642 _D("fake launch pid : %d\n", pid);
643 if ((ret = __fake_launch_app(cmd, pid, kb)) < 0)
644 _E("fake_launch failed. error code = %d", ret);
645 PERF("fake launch done");
651 _static_ void __real_send(int clifd, int ret)
653 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
654 if (errno == EPIPE) {
655 _E("send failed due to EPIPE.\n");
657 _E("send fail to client");
663 _static_ void __send_result_to_caller(int clifd, int ret)
667 int cmdline_changed = 0;
668 int cmdline_exist = 0;
674 __real_send(clifd, ret);
677 /* check normally was launched?*/
680 cmdline = __proc_get_cmdline_bypid(ret);
681 if (cmdline == NULL) {
682 _E("error founded when being launched with %d", ret);
684 } else if (strcmp(cmdline, launchpad_cmdline)) {
693 _D("-- now wait to change cmdline --");
694 usleep(50 * 1000); /* 50ms sleep*/
696 } while (wait_count <= 10); /* max 50*10ms will be sleep*/
698 if ((!cmdline_exist) && (!cmdline_changed)) {
699 __real_send(clifd, -1); /* abnormally launched*/
703 if (!cmdline_changed)
704 _E("process launched, but cmdline not changed");
706 __real_send(clifd, ret);
710 _static_ void __launchpad_main_loop(int main_fd)
713 app_pkt_t *pkt = NULL;
714 app_info_from_db *menu_info = NULL;
716 const char *pkg_name = NULL;
717 const char *app_path = NULL;
722 char sock_path[UNIX_PATH_MAX] = {0,};
724 pkt = __app_recv_raw(main_fd, &clifd, &cr);
726 _D("packet is NULL");
730 kb = bundle_decode(pkt->data, pkt->len);
732 _D("bundle decode error");
737 PERF("packet processing start");
739 if (pkt->cmd == APP_RESULT || pkt->cmd == APP_CANCEL) {
740 pid = __foward_cmd(pkt->cmd, kb, cr.pid);
744 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
745 _D("pkg name : %s\n", pkg_name);
747 if (pkt->cmd == APP_TERM_BY_PID || pkt->cmd == APP_RESUME_BY_PID ||
748 pkt->cmd == APP_KILL_BY_PID) {
749 pid = __app_process_by_pid(pkt->cmd, pkg_name, &cr);
753 menu_info = _get_app_info_from_db_by_pkgname(pkg_name);
754 if (menu_info == NULL) {
755 _D("such pkg no found");
759 app_path = _get_app_path(menu_info);
760 if(app_path == NULL) {
761 _E("app_path is NULL");
764 if (app_path[0] != '/') {
765 _D("app_path is not absolute path");
769 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
770 pkg_name = _get_pkgname(menu_info);
772 PERF("get package information & modify bundle done");
774 if (_is_app_multi_inst(menu_info) == 0)
775 pid = __proc_iter_cmdline(NULL, (void *)app_path);
777 PERF("find pid by searching proc file system done");
783 _D("caller process & callee process is same.[%s:%d]",
785 pid = -ELOCALLAUNCH_ID;
786 } else if ((ret = __nofork_processing(pkt->cmd, pid, kb)) < 0)
792 _E("lock up test log(no error) : fork done");
797 __signal_unset_sigchld();
800 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
803 PERF("prepare exec - first done");
804 _E("lock up test log(no error) : prepare exec - first done");
806 if (__prepare_exec(pkg_name, app_path,
807 menu_info, kb) < 0) {
808 _E("preparing work fail to launch - "
809 "can not launch %s\n", pkg_name);
813 PERF("prepare exec - second done");
814 _E("lock up test log(no error) : prepare exec - second done");
816 __real_launch(app_path, kb);
820 _D("==> real launch pid : %d %s\n", pid, app_path);
824 __send_result_to_caller(clifd, pid);
828 ret = ac_check_launch_privilege(pkg_name, menu_info->pkg_type, pid);
829 _D("ac_check_launch_privilege : %d", ret);
832 __add_history(cr.pid, pid, pkg_name, NULL, app_path);
836 __add_history(cr.pid, pid, pkg_name, kb, app_path);
839 _D("no launch case");
843 if (menu_info != NULL)
844 _free_app_info_from_db(menu_info);
851 /* Active Flusing for Daemon */
852 if (initialized > AUL_POLL_CNT) {
853 sqlite3_release_memory(SQLITE_FLUSH_MAX);
860 _static_ int __launchpad_pre_init(int argc, char **argv)
870 /* get my(launchpad) command line*/
871 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
872 if (launchpad_cmdline == NULL) {
873 _E("launchpad cmdline fail to get");
876 _D("launchpad cmdline = %s", launchpad_cmdline);
878 /* create launchpad sock */
879 fd = __create_server_sock(LAUNCHPAD_PID);
881 _E("server sock error");
885 __preload_init(argc, argv);
890 _static_ int __launchpad_post_init()
892 /* Setting this as a global variable to keep track
893 of launchpad poll cnt */
894 /* static int initialized = 0;*/
902 if (__signal_set_sigchld() < 0)
910 int main(int argc, char **argv)
913 struct pollfd pfds[POLLFD_MAX];
916 /* init without concerning X & EFL*/
917 main_fd = __launchpad_pre_init(argc, argv);
919 _E("launchpad pre init failed");
923 pfds[0].fd = main_fd;
924 pfds[0].events = POLLIN;
928 if (poll(pfds, POLLFD_MAX, -1) < 0)
931 /* init with concerning X & EFL (because of booting
933 if (__launchpad_post_init() < 0) {
934 _E("launcpad post init failed");
938 for (i = 0; i < POLLFD_MAX; i++) {
939 if ((pfds[i].revents & POLLIN) != 0) {
940 __launchpad_main_loop(pfds[i].fd);