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>
61 #include "fileutils.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
69 #define PATH_TMP "/tmp"
70 #define PATH_DATA "/data"
72 #define SDK_CODE_COVERAGE "CODE_COVERAGE"
73 #define SDK_DEBUG "DEBUG"
74 #define SDK_DYNAMIC_ANALYSIS "DYNAMIC_ANALYSIS"
75 #define SDK_UNIT_TEST "UNIT_TEST"
76 #define SDK_VALGRIND "VALGRIND"
78 /* DLP is short for debug-launchpad */
79 #define DLP_K_DEBUG_ARG "__DLP_DEBUG_ARG__"
80 #define DLP_K_UNIT_TEST_ARG "__DLP_UNIT_TEST_ARG__"
81 #define DLP_K_VALGRIND_ARG "__DLP_VALGRIND_ARG__"
83 #define PATH_GDBSERVER "/home/developer/sdk_tools/gdbserver/gdbserver"
84 #define PATH_VALGRIND "/home/developer/sdk_tools/valgrind/usr/bin/valgrind"
85 #define PATH_DA_SO "/usr/lib/da_probe_osp.so"
86 #define PATH_NATIVE_APP "/opt/apps/"
88 static char *launchpad_cmdline;
89 static int initialized = 0;
93 void __set_env(app_info_from_db * menu_info, bundle * kb);
94 int __prepare_exec(const char *pkg_name,
95 const char *app_path, app_info_from_db * menu_info,
97 int __fake_launch_app(int cmd, int pid, bundle * kb);
98 char **__create_argc_argv(bundle * kb, int *margc, const char *app_path);
99 int __normal_fork_exec(int argc, char **argv);
100 void __real_launch(const char *app_path, bundle * kb);
101 static inline int __parser(const char *arg, char *out, int out_size);
102 void __modify_bundle(bundle * kb, int caller_pid,
103 app_info_from_db * menu_info, int cmd);
104 int __send_to_sigkill(int pid);
105 int __term_app(int pid);
106 void __real_send(int clifd, int ret);
107 void __send_result_to_caller(int clifd, int ret);
108 void __launchpad_main_loop(int main_fd);
109 int __launchpad_pre_init(int argc, char **argv);
110 int __launchpad_post_init();
112 extern ail_error_e ail_db_close(void);
118 char buf[MAX_LOCAL_BUFSZ];
121 /* we should reset oomadj value as default because child
122 inherits from parent oom_adj*/
123 snprintf(buf, MAX_LOCAL_BUFSZ, "/proc/%d/oom_adj", getpid());
124 fp = fopen(buf, "w");
127 fprintf(fp, "%d", -16);
131 void __set_sdk_env(app_info_from_db* menu_info, char* str) {
132 char buf_pkgname[MAX_LOCAL_BUFSZ];
133 char buf[MAX_LOCAL_BUFSZ];
136 _D("key : %s / value : %s", AUL_K_SDK, str);
137 /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
138 /* GCOV_PREFIX contains the prefix to add to the absolute paths in the object file. */
139 /* Prefix can be absolute, or relative. The default is no prefix. */
140 /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
141 /* to stripoff the hardwired absolute paths. Default value is 0. */
142 if (strncmp(str, SDK_CODE_COVERAGE, strlen(str)) == 0) {
143 strncpy(buf_pkgname,_get_pkgname(menu_info),MAX_LOCAL_BUFSZ-1);
144 buf_pkgname[MAX_LOCAL_BUFSZ-1]='\0';
145 snprintf(buf, MAX_LOCAL_BUFSZ, PATH_TMP"/%s"PATH_DATA, strtok(buf_pkgname,"."));
146 ret = setenv("GCOV_PREFIX", buf, 1);
147 _D("GCOV_PREFIX : %d", ret);
148 ret = setenv("GCOV_PREFIX_STRIP", "0", 1);
149 _D("GCOV_PREFIX_STRIP : %d", ret);
150 } else if (strncmp(str, SDK_DYNAMIC_ANALYSIS, strlen(str)) == 0) {
151 ret = setenv("LD_PRELOAD", PATH_DA_SO, 1);
152 _D("LD_PRELOAD : %d", ret);
157 void __set_env(app_info_from_db * menu_info, bundle * kb)
160 const char **str_array;
164 setenv("PKG_NAME", _get_pkgname(menu_info), 1);
168 str = bundle_get_val(kb, AUL_K_STARTTIME);
170 setenv("APP_START_TIME", str, 1);
172 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
173 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
174 if(str_array != NULL) {
175 for (i = 0; i < len; i++) {
176 _D("index : [%d]", i);
177 __set_sdk_env(menu_info, (char *)str_array[i]);
181 str = bundle_get_val(kb, AUL_K_SDK);
183 __set_sdk_env(menu_info, (char *)str);
186 if (menu_info->hwacc != NULL)
187 setenv("HWACC", menu_info->hwacc, 1);
190 int __prepare_exec(const char *pkg_name,
191 const char *app_path, app_info_from_db * menu_info,
195 char process_name[AUL_PR_NAME];
198 /* Set new session ID & new process group ID*/
199 /* In linux, child can set new session ID without check permission */
200 /* TODO : should be add to check permission in the kernel*/
203 __preexec_run(menu_info->pkg_type, pkg_name, app_path);
209 if(bundle_get_val(kb, AUL_K_PRIVACY_APPID) == NULL) {
210 _D("pkg_name : %s / pkg_type : %s / app_path : %s ", pkg_name, menu_info->pkg_type, app_path);
211 if ((ret = __set_access(pkg_name, menu_info->pkg_type, app_path)) < 0) {
212 _D("fail to set privileges - check your package's credential : %d\n", ret);
216 /* SET DUMPABLE - for coredump*/
217 prctl(PR_SET_DUMPABLE, 1);
219 /* SET PROCESS NAME*/
220 if (app_path == NULL) {
221 _D("app_path should not be NULL - check menu db");
224 file_name = strrchr(app_path, '/') + 1;
225 if (file_name == NULL) {
226 _D("can't locate file name to execute");
229 memset(process_name, '\0', AUL_PR_NAME);
230 snprintf(process_name, AUL_PR_NAME, "%s", file_name);
231 prctl(PR_SET_NAME, process_name);
234 __set_env(menu_info, kb);
239 int __fake_launch_app(int cmd, int pid, bundle * kb)
245 bundle_encode(kb, &kb_data, &datalen);
246 if ((ret = __app_send_raw(pid, cmd, kb_data, datalen)) < 0)
247 _E("error request fake launch - error code = %d", ret);
252 char** __add_arg(bundle * kb, char **argv, int *margc, const char *key)
254 const char *str = NULL;
255 const char **str_array = NULL;
258 char ** new_argv = NULL;
260 if(bundle_get_type(kb, key) & BUNDLE_TYPE_ARRAY) {
261 str_array = bundle_get_str_array(kb, key, &len);
263 str = bundle_get_val(kb, key);
269 if(str_array != NULL) {
270 if(strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0
271 || strncmp(key, DLP_K_VALGRIND_ARG, strlen(key)) == 0)
273 new_argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+2));
275 _E("realloc fail (key = %s)", key);
278 for(i=*margc+len+1; i-(len+1)>=0; i--) {
279 new_argv[i] = new_argv[i-(len+1)];
281 // need to add new_argv[0]
282 for(i=0; i<len; i++) {
283 new_argv[1+i] = strdup(str_array[i]);
285 len++; /* gdbserver or valgrind */
286 _D("uid : %d", getuid());
287 _D("euid : %d", geteuid());
288 _D("gid : %d", getgid());
289 _D("egid : %d", getegid());
291 new_argv = (char **) realloc(argv, sizeof(char *) * (*margc+len+1));
293 _E("realloc fail (key = %s)", key);
296 for(i=0; i<len; i++) {
297 new_argv[*margc+i] = strdup(str_array[i]);
300 new_argv[*margc+len] = NULL;
303 if(strncmp(key, DLP_K_DEBUG_ARG, strlen(key)) == 0
304 || strncmp(key, DLP_K_VALGRIND_ARG, strlen(key)) == 0)
306 new_argv = (char **) realloc(argv, sizeof(char *) * (*margc+2));
308 _E("realloc fail (key = %s)", key);
311 for(i=*margc+1; i-1>=0; i--) {
312 new_argv[i] = new_argv[i-1];
314 // need to add new_argv[0]
319 if(new_argv==NULL) return argv;
323 char **__create_argc_argv(bundle * kb, int *margc, const char *app_path)
326 char **new_argv = NULL;
329 const char *str = NULL;
330 const char **str_array = NULL;
334 argc = bundle_export_to_argv(kb, &argv);
336 argv[0] = strdup(app_path);
338 _E("bundle_export_to_argv error");
342 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
343 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
345 str = bundle_get_val(kb, AUL_K_SDK);
351 if(str_array != NULL) {
352 for (i = 0; i < len; i++) {
353 if(str_array[i] == NULL) break;
354 _D("index : [%d]", i);
355 if (strncmp(str_array[i], SDK_DEBUG, strlen(str_array[i])) == 0) {
356 char buf[MAX_LOCAL_BUFSZ];
357 if (argv[0]) free(argv[0]);
358 sprintf(buf,"%s.exe",app_path);
359 argv[0] = strdup(buf);
360 new_argv = __add_arg(kb, argv, &argc, DLP_K_DEBUG_ARG);
361 new_argv[0] = strdup(PATH_GDBSERVER);
362 } else if (strncmp(str_array[i], SDK_VALGRIND, strlen(str_array[i])) == 0) {
363 new_argv = __add_arg(kb, argv, &argc, DLP_K_VALGRIND_ARG);
364 new_argv[0] = strdup(PATH_VALGRIND);
365 } else if (strncmp(str_array[i], SDK_UNIT_TEST, strlen(str_array[i])) == 0) {
366 new_argv = __add_arg(kb, argv, &argc, DLP_K_UNIT_TEST_ARG);
372 if(new_argv==NULL) return argv;
376 int __normal_fork_exec(int argc, char **argv)
378 _D("start real fork and exec\n");
380 if (execv(argv[0], argv) < 0) { /* Flawfinder: ignore */
381 if (errno == EACCES) {
382 _E("such a file is no executable - %s", argv[0]);
384 _E("unknown executable error - %s", argv[0]);
392 void __real_launch(const char *app_path, bundle * kb)
398 app_argv = __create_argc_argv(kb, &app_argc, app_path);
400 for (i = 0; i < app_argc; i++)
401 _D("input argument %d : %s##", i, app_argv[i]);
403 PERF("setup argument done");
404 _D("lock up test log(no error) : setup argument done");
406 /* Temporary log: launch time checking */
407 LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
409 __normal_fork_exec(app_argc, app_argv);
411 for(i=0; i<app_argc; i++) {
412 if(app_argv[i]) free(app_argv[i]);
419 * Parsing original app path to retrieve default bundle
421 * -1 : Invalid sequence
422 * -2 : Buffer overflow
425 static inline int __parser(const char *arg, char *out, int out_size)
429 char *start_out = out;
431 if (arg == NULL || out == NULL) {
432 /* Handles null buffer*/
436 for (i = 0; out_size > 1; i++) {
460 case 2: /* escape start*/
475 case 4: /* character escape*/
476 if (arg[i] == '\0') {
486 if (out != start_out) {
495 return -1; /* error*/
496 case 7: /* terminate*/
513 void __modify_bundle(bundle * kb, int caller_pid,
514 app_info_from_db * menu_info, int cmd)
516 bundle_del(kb, AUL_K_PKG_NAME);
517 bundle_del(kb, AUL_K_EXEC);
518 bundle_del(kb, AUL_K_PACKAGETYPE);
519 bundle_del(kb, AUL_K_HWACC);
521 /* Parse app_path to retrieve default bundle*/
522 if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_OPEN || cmd == APP_RESUME) {
524 char exe[MAX_PATH_LEN];
527 ptr = _get_original_app_path(menu_info);
529 flag = __parser(ptr, exe, sizeof(exe));
535 _D("parsing app_path: EXEC - %s\n", exe);
538 flag = __parser(ptr, key, sizeof(key));
543 flag = __parser(ptr, value, sizeof(value));
548 /*bundle_del(kb, key);*/
549 bundle_add(kb, key, value);
551 } else if (flag == 0) {
552 _D("parsing app_path: No arguments\n");
554 _D("parsing app_path: Invalid argument\n");
559 int __send_to_sigkill(int pid)
567 if (killpg(pgid, SIGKILL) < 0)
573 int __term_app(int pid)
577 (pid, APP_TERM_BY_PID, (unsigned char *)&dummy, sizeof(int)) < 0) {
578 _D("terminate packet send error - use SIGKILL");
579 if (__send_to_sigkill(pid) < 0) {
580 _E("fail to killing - %d\n", pid);
588 static int __get_caller_pid(bundle *kb)
593 pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
597 pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
609 int __foward_cmd(int cmd, bundle *kb, int cr_pid)
612 char tmp_pid[MAX_PID_STR_BUFSZ];
617 if ((pid = __get_caller_pid(kb)) < 0)
620 snprintf(tmp_pid, MAX_PID_STR_BUFSZ, "%d", cr_pid);
622 bundle_add(kb, AUL_K_CALLEE_PID, tmp_pid);
624 bundle_encode(kb, &kb_data, &datalen);
625 if ((res = __app_send_raw_with_noreply(pid, cmd, kb_data, datalen)) < 0)
633 void __real_send(int clifd, int ret)
635 if (send(clifd, &ret, sizeof(int), MSG_NOSIGNAL) < 0) {
636 if (errno == EPIPE) {
637 _E("send failed due to EPIPE.\n");
639 _E("send fail to client");
645 void __send_result_to_caller(int clifd, int ret)
649 int cmdline_changed = 0;
650 int cmdline_exist = 0;
656 __real_send(clifd, ret);
659 /* check normally was launched?*/
662 cmdline = __proc_get_cmdline_bypid(ret);
663 if (cmdline == NULL) {
664 _E("error founded when being launched with %d", ret);
666 } else if (strcmp(cmdline, launchpad_cmdline)) {
675 _D("-- now wait to change cmdline --");
676 usleep(50 * 1000); /* 50ms sleep*/
678 } while (wait_count <= 20); /* max 50*20ms will be sleep*/
680 if ((!cmdline_exist) && (!cmdline_changed)) {
681 _E("abnormally launched");
682 __real_send(clifd, -1); /* abnormally launched*/
686 if (!cmdline_changed)
687 _E("process launched, but cmdline not changed");
689 __real_send(clifd, ret);
693 static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
694 const char *pkgname, bundle *kb)
696 app_info_from_db *menu_info;
698 menu_info = calloc(1, sizeof(app_info_from_db));
699 if (menu_info == NULL) {
703 menu_info->pkg_name = strdup(pkgname);
704 menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC));
705 if (menu_info->app_path != NULL)
706 menu_info->original_app_path = strdup(menu_info->app_path);
707 menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE));
708 menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC));
710 if (!_get_app_path(menu_info)) {
711 _free_app_info_from_db(menu_info);
721 int get_native_appid(const char* app_path, char** appid) {
722 int rc = smack_lgetlabel(app_path, appid, SMACK_LABEL_ACCESS);
724 if (rc != 0 || *appid == NULL) {
725 _E("smack_lgetlabel fail");
729 if (strlen(*appid)!=APPID_LEN) {
730 _E("wrong native appid : %s", *appid);
734 if (strlen(app_path)<sizeof(PATH_NATIVE_APP)+APPID_LEN-1) {
735 _E("wrong native app_path : %s", app_path);
737 } else if (strncmp(app_path,PATH_NATIVE_APP,sizeof(PATH_NATIVE_APP)-1)
738 || strncmp(&app_path[sizeof(PATH_NATIVE_APP)-1],*appid,APPID_LEN)) {
739 _E("wrong native app_path : %s", app_path);
743 _D("get_appid return : %s", *appid);
747 int apply_smack_rules(const char* subject, const char* object, const char* access_type) {
748 struct smack_accesses *rules = NULL;
750 _D("apply_smack_rules : %s %s %s", subject, object, access_type);
752 if (smack_accesses_new(&rules)) {
753 _E("smack_accesses_new fail");
757 if (smack_accesses_add(rules, subject, object, access_type)) {
758 smack_accesses_free(rules);
759 _E("smack_accesses_add fail");
763 if (smack_accesses_apply(rules)) {
764 smack_accesses_free(rules);
765 _E("smack_accesses_apply fail");
769 smack_accesses_free(rules);
774 void __launchpad_main_loop(int main_fd)
777 app_pkt_t *pkt = NULL;
778 app_info_from_db *menu_info = NULL;
780 const char *pkg_name = NULL;
781 const char *app_path = NULL;
785 int is_real_launch = 0;
787 char sock_path[UNIX_PATH_MAX] = {0,};
789 pkt = __app_recv_raw(main_fd, &clifd, &cr);
791 _D("packet is NULL");
795 kb = bundle_decode(pkt->data, pkt->len);
797 _D("bundle decode error");
802 PERF("packet processing start");
804 pkg_name = bundle_get_val(kb, AUL_K_PKG_NAME);
805 _D("pkg name : %s\n", pkg_name);
807 menu_info = _get_app_info_from_bundle_by_pkgname(pkg_name, kb);
808 if (menu_info == NULL) {
809 _D("such pkg no found");
813 app_path = _get_app_path(menu_info);
814 if(app_path == NULL) {
815 _E("app_path is NULL");
818 if (app_path[0] != '/') {
819 _D("app_path is not absolute path");
823 __modify_bundle(kb, cr.pid, menu_info, pkt->cmd);
824 pkg_name = _get_pkgname(menu_info);
826 PERF("get package information & modify bundle done");
829 const char *str = NULL;
830 const char **str_array = NULL;
833 if(bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
834 str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
836 str = bundle_get_val(kb, AUL_K_SDK);
842 if(str_array != NULL) {
844 for (i = 0; i < len; i++) {
845 if(str_array[i] == NULL) break;
846 if (strncmp(str_array[i], SDK_DEBUG, strlen(str_array[i])) == 0) {
848 int rc = get_native_appid(app_path,&appid);
849 if(rc!=0 || appid==NULL) {
850 _E("unable to get native appid");
851 if(appid) free(appid);
853 }else if(apply_smack_rules("sdbd",appid,"w")) {
854 _E("unable to set sdbd rules");
855 if(appid) free(appid);
858 if(appid) free(appid);
860 // FIXME: set gdbfolder to 755 also
861 if(dlp_chmod(PATH_GDBSERVER, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH, 1) < 0)
863 _D("unable to set 755 to %s", PATH_GDBSERVER);
872 _D("lock up test log(no error) : fork done");
876 __signal_unset_sigchld();
879 snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, getpid());
882 PERF("prepare exec - first done");
883 _D("lock up test log(no error) : prepare exec - first done");
885 if (__prepare_exec(pkg_name, app_path,
886 menu_info, kb) < 0) {
887 _E("preparing work fail to launch - "
888 "can not launch %s\n", pkg_name);
892 PERF("prepare exec - second done");
893 _D("lock up test log(no error) : prepare exec - second done");
895 __real_launch(app_path, kb);
899 _D("==> real launch pid : %d %s\n", pid, app_path);
904 __send_result_to_caller(clifd, pid);
907 if (is_real_launch) {
909 __signal_block_sigchld();
910 __send_app_launch_signal(pid);
911 __signal_unblock_sigchld();
915 if (menu_info != NULL)
916 _free_app_info_from_db(menu_info);
923 /* Active Flusing for Daemon */
924 if (initialized > AUL_POLL_CNT) {
925 sqlite3_release_memory(SQLITE_FLUSH_MAX);
932 int __launchpad_pre_init(int argc, char **argv)
939 /* get my(launchpad) command line*/
940 launchpad_cmdline = __proc_get_cmdline_bypid(getpid());
941 if (launchpad_cmdline == NULL) {
942 _E("launchpad cmdline fail to get");
945 _D("launchpad cmdline = %s", launchpad_cmdline);
947 /* create launchpad sock */
948 fd = __create_server_sock(DEBUG_LAUNCHPAD_PID);
950 _E("server sock error");
954 __preload_init(argc, argv);
956 __preexec_init(argc, argv);
961 int __launchpad_post_init()
963 /* Setting this as a global variable to keep track
964 of launchpad poll cnt */
965 /* static int initialized = 0;*/
972 if (__signal_set_sigchld() < 0)
980 int main(int argc, char **argv)
983 struct pollfd pfds[POLLFD_MAX];
986 /* init without concerning X & EFL*/
987 main_fd = __launchpad_pre_init(argc, argv);
989 _E("launchpad pre init failed");
993 pfds[0].fd = main_fd;
994 pfds[0].events = POLLIN;
998 if (poll(pfds, POLLFD_MAX, -1) < 0)
1001 /* init with concerning X & EFL (because of booting
1003 if (__launchpad_post_init() < 0) {
1004 _E("launcpad post init failed");
1008 for (i = 0; i < POLLFD_MAX; i++) {
1009 if ((pfds[i].revents & POLLIN) != 0) {
1010 __launchpad_main_loop(pfds[i].fd);