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 <sys/smack.h>
62 #define _static_ static inline
64 #define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
65 #define AUL_POLL_CNT 15
66 #define AUL_PR_NAME 16
68 #define PATH_TMP "/tmp"
69 #define PATH_DATA "/data"
71 #define SDK_CODE_COVERAGE "CODE_COVERAGE"
72 #define SDK_DEBUG "DEBUG"
73 #define SDK_DYNAMIC_ANALYSIS "DYNAMIC_ANALYSIS"
74 #define SDK_UNIT_TEST "UNIT_TEST"
76 /* DLP is short for debug-launchpad */
77 #define DLP_K_DEBUG_ARG "__DLP_DEBUG_ARG__"
78 #define DLP_K_UNIT_TEST_ARG "__DLP_UNIT_TEST_ARG__"
80 #define PATH_GDBSERVER "/home/developer/sdk_tools/gdbserver/gdbserver"
81 #define PATH_DA_SO "/usr/lib/da_probe_osp.so"
82 #define PATH_NATIVE_APP "/opt/apps/"
84 static char *launchpad_cmdline;
85 static int initialized = 0;
88 _static_ void __set_oom();
89 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb);
90 _static_ int __prepare_exec(const char *pkg_name,
91 const char *app_path, app_info_from_db * menu_info,
93 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb);
94 _static_ char **__create_argc_argv(bundle * kb, int *margc, const char *app_path);
95 _static_ int __normal_fork_exec(int argc, char **argv);
96 _static_ void __real_launch(const char *app_path, bundle * kb);
97 static inline int __parser(const char *arg, char *out, int out_size);
98 _static_ void __modify_bundle(bundle * kb, int caller_pid,
99 app_info_from_db * menu_info, int cmd);
100 _static_ int __child_raise_win_by_x(int pid, void *priv);
101 _static_ int __raise_win_by_x(int pid);
102 _static_ int __send_to_sigkill(int pid);
103 _static_ int __term_app(int pid);
104 _static_ int __resume_app(int pid);
105 _static_ void __real_send(int clifd, int ret);
106 _static_ void __send_result_to_caller(int clifd, int ret);
107 _static_ void __launchpad_main_loop(int main_fd);
108 _static_ int __launchpad_pre_init(int argc, char **argv);
109 _static_ int __launchpad_post_init();
111 extern ail_error_e ail_db_close(void);
115 _static_ void __set_oom()
117 char buf[MAX_LOCAL_BUFSZ];
120 /* we should reset oomadj value as default because child
121 inherits from parent oom_adj*/
122 snprintf(buf, MAX_LOCAL_BUFSZ, "/proc/%d/oom_adj", getpid());
123 fp = fopen(buf, "w");
126 fprintf(fp, "%d", -16);
130 _static_ void __set_sdk_env(app_info_from_db* menu_info, char* str) {
131 char buf_pkgname[MAX_LOCAL_BUFSZ];
132 char buf[MAX_LOCAL_BUFSZ];
135 _D("key : %s / value : %s", AUL_K_SDK, str);
136 /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
137 /* GCOV_PREFIX contains the prefix to add to the absolute paths in the object file. */
138 /* Prefix can be absolute, or relative. The default is no prefix. */
139 /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
140 /* to stripoff the hardwired absolute paths. Default value is 0. */
141 if (strncmp(str, SDK_CODE_COVERAGE, strlen(str)) == 0) {
142 strncpy(buf_pkgname,_get_pkgname(menu_info),MAX_LOCAL_BUFSZ-1);
143 buf_pkgname[MAX_LOCAL_BUFSZ-1]='\0';
144 snprintf(buf, MAX_LOCAL_BUFSZ, PATH_TMP"/%s"PATH_DATA, strtok(buf_pkgname,"."));
145 ret = setenv("GCOV_PREFIX", buf, 1);
146 _D("GCOV_PREFIX : %d", ret);
147 ret = setenv("GCOV_PREFIX_STRIP", "0", 1);
148 _D("GCOV_PREFIX_STRIP : %d", ret);
149 } else if (strncmp(str, SDK_DYNAMIC_ANALYSIS, strlen(str)) == 0) {
150 ret = setenv("LD_PRELOAD", PATH_DA_SO, 1);
151 _D("LD_PRELOAD : %d", ret);
156 _static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
159 const char **str_array;
163 setenv("PKG_NAME", _get_pkgname(menu_info), 1);
167 str = bundle_get_val(kb, AUL_K_STARTTIME);
169 setenv("APP_START_TIME", str, 1);
171 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
172 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
173 if(str_array != NULL) {
174 for (i = 0; i < len; i++) {
175 _D("index : [%d]", i);
176 __set_sdk_env(menu_info, (char *)str_array[i]);
180 str = bundle_get_val(kb, AUL_K_SDK);
182 __set_sdk_env(menu_info, (char *)str);
185 if (menu_info->hwacc != NULL)
186 setenv("HWACC", menu_info->hwacc, 1);
189 _static_ int __prepare_exec(const char *pkg_name,
190 const char *app_path, app_info_from_db * menu_info,
194 char process_name[AUL_PR_NAME];
197 /* Set new session ID & new process group ID*/
198 /* In linux, child can set new session ID without check permission */
199 /* TODO : should be add to check permission in the kernel*/
202 __preexec_run(menu_info->pkg_type, pkg_name, app_path);
208 if(bundle_get_val(kb, AUL_K_PRIVACY_APPID) == NULL) {
209 _D("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path);
210 if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) {
211 _D("fail to set privileges - check your package's credential : %d\n", ret);
215 /* SET DUMPABLE - for coredump*/
216 prctl(PR_SET_DUMPABLE, 1);
218 /* SET PROCESS NAME*/
219 if (app_path == NULL) {
220 _D("app_path should not be NULL - check menu db");
223 file_name = strrchr(app_path, '/') + 1;
224 if (file_name == NULL) {
225 _D("can't locate file name to execute");
228 memset(process_name, '\0', AUL_PR_NAME);
229 snprintf(process_name, AUL_PR_NAME, "%s", file_name);
230 prctl(PR_SET_NAME, process_name);
233 __set_env(menu_info, kb);
238 _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
244 bundle_encode(kb, &kb_data, &datalen);
245 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
246 _E("error request fake launch - error code = %d", ret);
251 _static_ char **__add_arg(bundle * kb, char **argv, int *margc, const char *key)
253 const char *str = NULL;
254 const char **str_array = NULL;
258 if(bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
259 str_array = bundle_get_str_array(kb, key, &len);
261 str = bundle_get_val(kb, key);
267 if(str_array != NULL) {
268 if(strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0) {
269 argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+2));
271 _E("realloc fail (key = %s)", key);
274 for(i=*margc+len+1; i-(len+1)>=0; i--) {
275 argv[i] = argv[i-(len+1)];
277 argv[0] = strdup(PATH_GDBSERVER);
278 for(i=0; i<len; i++) {
279 argv[1+i] = strdup(str_array[i]);
281 len++; /* gdbserver */
283 argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+1));
285 _E("realloc fail (key = %s)", key);
288 for(i=0; i<len; i++) {
289 argv[*margc+i] = strdup(str_array[i]);
292 argv[*margc+len] = NULL;
299 _static_ char **__create_argc_argv(bundle * kb, int *margc, const char *app_path)
304 const char *str = NULL;
305 const char **str_array = NULL;
309 char buf[MAX_LOCAL_BUFSZ];
311 argc = bundle_export_to_argv(kb, &argv);
312 sprintf(buf,"%s.exe",app_path);
313 argv[0] = strdup(buf);
315 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
316 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
318 str = bundle_get_val(kb, AUL_K_SDK);
324 if(str_array != NULL) {
325 for (i = 0; i < len; i++) {
326 if(str_array[i] == NULL) break;
327 _D("index : [%d]", i);
328 if (strncmp(str_array[i], SDK_DEBUG, strlen(str_array[i])) == 0) {
329 argv = __add_arg(kb, argv, &argc, DLP_K_DEBUG_ARG);
330 } else if (strncmp(str_array[i], SDK_UNIT_TEST, strlen(str_array[i])) == 0) {
331 argv = __add_arg(kb, argv, &argc, DLP_K_UNIT_TEST_ARG);
340 _static_ int __normal_fork_exec(int argc, char **argv)
342 _D("start real fork and exec\n");
344 if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
345 if (errno == EACCES) {
346 _E("such a file is no executable - %s", argv[0]);
348 _E("unknown executable error - %s", argv[0]);
356 _static_ void __real_launch(const char *app_path, bundle * kb)
362 app_argv = __create_argc_argv(kb, &app_argc, app_path);
364 for (i = 0; i < app_argc; i++)
365 _D("input argument %d : %s##", i, app_argv[i]);
367 PERF("setup argument done");
368 _D("lock up test log(no error) : setup argument done");
370 /* Temporary log: launch time checking */
371 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
373 __normal_fork_exec(app_argc, app_argv);
375 for(i=0; i<app_argc; i++) {
376 if(app_argv[i]) free(app_argv[i]);
383 * Parsing original app path to retrieve default bundle
385 * -1 : Invalid sequence
386 * -2 : Buffer overflow
389 static inline int __parser(const char *arg, char *out, int out_size)
393 char *start_out = out;
395 if (arg == NULL || out == NULL) {
396 /* Handles null buffer*/
400 for (i = 0; out_size > 1; i++) {
424 case 2: /* escape start*/
439 case 4: /* character escape*/
440 if (arg[i] == '\0') {
450 if (out != start_out) {
459 return -1; /* error*/
460 case 7: /* terminate*/
477 _static_ void __modify_bundle(bundle * kb, int caller_pid,
478 app_info_from_db * menu_info, int cmd)
480 bundle_del(kb, AUL_K_PKG_NAME);
481 bundle_del(kb, AUL_K_EXEC);
482 bundle_del(kb, AUL_K_PACKAGETYPE);
483 bundle_del(kb, AUL_K_HWACC);
485 /* Parse app_path to retrieve default bundle*/
486 if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_OPEN || cmd == APP_RESUME) {
488 char exe[MAX_PATH_LEN];
491 ptr = _get_original_app_path(menu_info);
493 flag = __parser(ptr, exe, sizeof(exe));
499 _D("parsing app_path: EXEC - %s\n", exe);
502 flag = __parser(ptr, key, sizeof(key));
507 flag = __parser(ptr, value, sizeof(value));
512 /*bundle_del(kb, key);*/
513 bundle_add(kb, key, value);
515 } else if (flag == 0) {
516 _D("parsing app_path: No arguments\n");
518 _D("parsing app_path: Invalid argument\n");
523 _static_ int __child_raise_win_by_x(int pid, void *priv)
525 return x_util_raise_win(pid);
528 _static_ int __raise_win_by_x(int pid)
531 if (x_util_raise_win(pid) == 0)
534 /* support app launched by shell script*/
536 _D("X raise failed. try to find first child & raise it - c:%d p:%d\n",
541 if (__proc_iter_pgid(pgid, __child_raise_win_by_x, NULL) < 0)
547 _static_ int __send_to_sigkill(int pid)
555 if (killpg(pgid, SIGKILL) < 0)
561 _static_ int __term_app(int pid)
565 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
566 _D("terminate packet send error - use SIGKILL");
567 if (__send_to_sigkill(pid) < 0) {
568 _E("fail to killing - %d\n", pid);
576 _static_ int __resume_app(int pid)
581 __app_send_raw(pid, APP_RESUME_BY_PID, (unsigned char *)&dummy,
584 _E("resume packet timeout error");
586 _D("resume packet send error - use raise win");
587 if (__raise_win_by_x(pid) < 0) {
588 _E("raise failed - %d resume fail\n", pid);
589 _E("we will term the app - %d\n", pid);
590 __send_to_sigkill(pid);
600 static int __get_caller_pid(bundle *kb)
605 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
609 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
621 _static_ int __foward_cmd(int cmd, bundle *kb, int cr_pid)
624 char tmp_pid[MAX_PID_STR_BUFSZ];
629 if ((pid = __get_caller_pid(kb)) < 0)
632 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
634 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
636 bundle_encode(kb, &kb_data, &datalen);
637 if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0)
645 _static_ void __real_send(int clifd, int ret)
647 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
648 if (errno == EPIPE) {
649 _E("send failed due to EPIPE.\n");
651 _E("send fail to client");
657 _static_ void __send_result_to_caller(int clifd, int ret)
661 int cmdline_changed = 0;
662 int cmdline_exist = 0;
668 __real_send(clifd, ret);
671 /* check normally was launched?*/
674 cmdline = __proc_get_cmdline_bypid(ret);
675 if (cmdline == NULL) {
676 _E("error founded when being launched with %d", ret);
678 } else if (strcmp(cmdline, launchpad_cmdline)) {
687 _D("-- now wait to change cmdline --");
688 usleep(50 * 1000); /* 50ms sleep*/
690 } while (wait_count <= 20); /* max 50*20ms will be sleep*/
692 if ((!cmdline_exist) && (!cmdline_changed)) {
693 __real_send(clifd, -1); /* abnormally launched*/
697 if (!cmdline_changed)
698 _E("process launched, but cmdline not changed");
700 __real_send(clifd, ret);
704 static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
705 const char *pkgname, bundle *kb)
707 app_info_from_db *menu_info;
709 menu_info = calloc(1, sizeof(app_info_from_db));
710 if (menu_info == NULL) {
714 menu_info->pkg_name = strdup(pkgname);
715 menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC));
716 if (menu_info->app_path != NULL)
717 menu_info->original_app_path = strdup(menu_info->app_path);
718 menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE));
719 menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC));
721 if (!_get_app_path(menu_info)) {
722 _free_app_info_from_db(menu_info);
732 int get_native_appid(const char* app_path, char** appid) {
733 int rc = smack_lgetlabel(app_path, appid, SMACK_LABEL_ACCESS);
735 if (rc != 0 || *appid == NULL) {
736 _E("smack_lgetlabel fail");
740 if (strlen(*appid)!=APPID_LEN) {
741 _E("wrong native appid : %s", *appid);
745 if (strlen(app_path)<sizeof(PATH_NATIVE_APP)+APPID_LEN-1) {
746 _E("wrong native app_path : %s", app_path);
748 } else if (strncmp(app_path,PATH_NATIVE_APP,sizeof(PATH_NATIVE_APP)-1)
749 || strncmp(&app_path[sizeof(PATH_NATIVE_APP)-1],*appid,APPID_LEN)) {
750 _E("wrong native app_path : %s", app_path);
754 _D("get_appid return : %s", *appid);
758 int apply_smack_rules(const char* subject, const char* object, const char* access_type) {
759 struct smack_accesses *rules = NULL;
761 _D("apply_smack_rules : %s %s %s", subject, object, access_type);
763 if (smack_accesses_new(&rules)) {
764 _E("smack_accesses_new fail");
768 if (smack_accesses_add(rules, subject, object, access_type)) {
769 smack_accesses_free(rules);
770 _E("smack_accesses_add fail");
774 if (smack_accesses_apply(rules)) {
775 smack_accesses_free(rules);
776 _E("smack_accesses_apply fail");
780 smack_accesses_free(rules);
785 _static_ void __launchpad_main_loop(int main_fd)
788 app_pkt_t *pkt = NULL;
789 app_info_from_db *menu_info = NULL;
791 const char *pkg_name = NULL;
792 const char *app_path = NULL;
796 int is_real_launch = 0;
798 char sock_path[UNIX_PATH_MAX] = {0,};
800 pkt = __app_recv_raw(main_fd, &clifd, &cr);
802 _D("packet is NULL");
806 kb = bundle_decode(pkt->data, pkt->len);
808 _D("bundle decode error");
813 PERF("packet processing start");
815 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
816 _D("pkg name : %s\n", pkg_name);
818 menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
819 if (menu_info == NULL) {
820 _D("such pkg no found");
824 app_path = _get_app_path(menu_info);
825 if(app_path == NULL) {
826 _E("app_path is NULL");
829 if (app_path[0] != '/') {
830 _D("app_path is not absolute path");
834 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
835 pkg_name = _get_pkgname(menu_info);
837 PERF("get package information & modify bundle done");
840 const char *str = NULL;
841 const char **str_array = NULL;
844 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
845 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
847 str = bundle_get_val(kb, AUL_K_SDK);
853 if(str_array != NULL) {
855 for (i = 0; i < len; i++) {
856 if(str_array[i] == NULL) break;
857 if (strncmp(str_array[i], SDK_DEBUG, strlen(str_array[i])) == 0) {
859 int rc = get_native_appid(app_path,&appid);
860 if(rc!=0 || appid==NULL) {
861 _E("unable to get native appid");
862 if(appid) free(appid);
864 }else if(apply_smack_rules("sdbd",appid,"w")) {
865 _E("unable to set sdbd rules");
866 if(appid) free(appid);
869 if(appid) free(appid);
877 _D("lock up test log(no error) : fork done");
881 __signal_unset_sigchld();
884 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
887 PERF("prepare exec - first done");
888 _D("lock up test log(no error) : prepare exec - first done");
890 if (__prepare_exec(pkg_name, app_path,
891 menu_info, kb) < 0) {
892 _E("preparing work fail to launch - "
893 "can not launch %s\n", pkg_name);
897 PERF("prepare exec - second done");
898 _D("lock up test log(no error) : prepare exec - second done");
900 __real_launch(app_path, kb);
904 _D("==> real launch pid : %d %s\n", pid, app_path);
909 __send_result_to_caller(clifd, pid);
912 if (is_real_launch) {
914 __signal_block_sigchld();
915 __send_app_launch_signal(pid);
916 __signal_unblock_sigchld();
920 if (menu_info != NULL)
921 _free_app_info_from_db(menu_info);
928 /* Active Flusing for Daemon */
929 if (initialized > AUL_POLL_CNT) {
930 sqlite3_release_memory(SQLITE_FLUSH_MAX);
937 _static_ int __launchpad_pre_init(int argc, char **argv)
944 /* get my(launchpad) command line*/
945 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
946 if (launchpad_cmdline == NULL) {
947 _E("launchpad cmdline fail to get");
950 _D("launchpad cmdline = %s", launchpad_cmdline);
952 /* create launchpad sock */
953 fd = __create_server_sock(DEBUG_LAUNCHPAD_PID);
955 _E("server sock error");
959 __preload_init(argc, argv);
961 __preexec_init(argc, argv);
966 _static_ int __launchpad_post_init()
968 /* Setting this as a global variable to keep track
969 of launchpad poll cnt */
970 /* static int initialized = 0;*/
977 if (__signal_set_sigchld() < 0)
985 int main(int argc, char **argv)
988 struct pollfd pfds[POLLFD_MAX];
991 /* init without concerning X & EFL*/
992 main_fd = __launchpad_pre_init(argc, argv);
994 _E("launchpad pre init failed");
998 pfds[0].fd = main_fd;
999 pfds[0].events = POLLIN;
1000 pfds[0].revents = 0;
1003 if (poll(pfds, POLLFD_MAX, -1) < 0)
1006 /* init with concerning X & EFL (because of booting
1008 if (__launchpad_post_init() < 0) {
1009 _E("launcpad post init failed");
1013 for (i = 0; i < POLLFD_MAX; i++) {
1014 if ((pfds[i].revents & POLLIN) != 0) {
1015 __launchpad_main_loop(pfds[i].fd);