#include <sys/wait.h>
#include <poll.h>
#include <sys/prctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
#include <malloc.h>
#include "app_sock.h"
#include <app-checker.h>
#include <sqlite3.h>
+#include "process_pool.h"
+#include "launchpad_util.h"
+
#define _static_ static inline
-#define POLLFD_MAX 1
-#define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
-#define AUL_POLL_CNT 15
-#define AUL_PR_NAME 16
-#define PKG_ID_LENGTH 11
-#define PATH_APP_ROOT "/opt/usr/apps"
-#define PATH_DATA "/data"
-#define SDK_CODE_COVERAGE "CODE_COVERAGE"
-#define SDK_DYNAMIC_ANALYSIS "DYNAMIC_ANALYSIS"
-#define PATH_DA_SO "/home/developer/sdk_tools/da/da_probe.so"
+#define SQLITE_FLUSH_MAX (1048576) /* (1024*1024) */
+#define AUL_POLL_CNT 15
+#define AUL_PR_NAME 16
+#define PKG_ID_LENGTH 11
+
+#define EXEC_DUMMY_EXPIRED 5
+#define DIFF(a,b) (((a)>(b))?(a)-(b):(b)-(a))
+#define WRT_CLIENT_PATH "/usr/bin/wrt-client"
+#define LOWEST_PRIO 20
+#define DUMMY_NONE 0
static char *launchpad_cmdline;
static int initialized = 0;
+static int dummy_process_pid = DUMMY_NONE;
+static int dummy_process_fd = -1;
+static int last_dummy_exec_time = 0;
+static int process_pool_disable = 0;
-_static_ void __set_oom();
-_static_ void __set_env(app_info_from_db * menu_info, bundle * kb);
_static_ int __prepare_exec(const char *pkg_name,
const char *app_path, app_info_from_db * menu_info,
bundle * kb);
_static_ char **__create_argc_argv(bundle * kb, int *margc);
_static_ int __normal_fork_exec(int argc, char **argv);
_static_ void __real_launch(const char *app_path, bundle * kb);
-static inline int __parser(const char *arg, char *out, int out_size);
-_static_ void __modify_bundle(bundle * kb, int caller_pid,
- app_info_from_db * menu_info, int cmd);
+_static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt);
_static_ int __child_raise_win_by_x(int pid, void *priv);
_static_ int __raise_win_by_x(int pid);
_static_ int __send_to_sigkill(int pid);
_static_ int __resume_app(int pid);
_static_ void __real_send(int clifd, int ret);
_static_ void __send_result_to_caller(int clifd, int ret);
-_static_ void __launchpad_main_loop(int main_fd);
+_static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd);
+_static_ void __launchpad_main_loop(int main_fd, int pool_fd);
_static_ int __launchpad_pre_init(int argc, char **argv);
_static_ int __launchpad_post_init();
extern ail_error_e ail_db_close(void);
-_static_ void __set_oom()
-{
- char buf[MAX_LOCAL_BUFSZ];
- FILE *fp;
-
- /* we should reset oomadj value as default because child
- * inherits from parent oom_adj*/
- snprintf(buf, MAX_LOCAL_BUFSZ, "/proc/%d/oom_adj", getpid());
- fp = fopen(buf, "w");
- if (fp == NULL) {
- return;
- }
- fprintf(fp, "%d", -16);
- fclose(fp);
-}
-
-_static_ void __set_sdk_env(app_info_from_db* menu_info, char* str)
-{
- char buf[MAX_LOCAL_BUFSZ];
- int ret;
-
- _D("key : %s / value : %s", AUL_K_SDK, str);
- /* http://gcc.gnu.org/onlinedocs/gcc/Cross_002dprofiling.html*/
- /* GCOV_PREFIX contains the prefix to add to the absolute paths in the
- *object file. */
- /* Prefix can be absolute, or relative. The default is no prefix.
- * */
- /* GCOV_PREFIX_STRIP indicates the how many initial directory names */
- /* to stripoff the hardwired absolute paths. Default value is 0. */
- if (strncmp(str, SDK_CODE_COVERAGE, strlen(str)) == 0) {
- snprintf(buf,
- MAX_LOCAL_BUFSZ,
- PATH_APP_ROOT "/%s"PATH_DATA,
- _get_pkgname(menu_info));
- ret = setenv("GCOV_PREFIX", buf, 1);
- _D("GCOV_PREFIX : %d", ret);
- ret = setenv("GCOV_PREFIX_STRIP", "4096", 1);
- _D("GCOV_PREFIX_STRIP : %d", ret);
- } else if (strncmp(str, SDK_DYNAMIC_ANALYSIS, strlen(str)) == 0) {
- ret = setenv("LD_PRELOAD", PATH_DA_SO, 1);
- _D("LD_PRELOAD : %d", ret);
- }
-}
-
-_static_ void __set_env(app_info_from_db * menu_info, bundle * kb)
-{
- const char *str;
-
- setenv("PKG_NAME", _get_pkgname(menu_info), 1);
-
- USE_ENGINE("gl")
-
- str = bundle_get_val(kb, AUL_K_STARTTIME);
- if (str != NULL) {
- setenv("APP_START_TIME", str, 1);
- }
-
- if (bundle_get_type(kb, AUL_K_SDK) & BUNDLE_TYPE_ARRAY) {
- int len;
- const char **str_array;
- str_array = bundle_get_str_array(kb, AUL_K_SDK, &len);
- if (str_array != NULL) {
- int i;
- for (i = 0; i < len; i++) {
- _D("index : [%d]", i);
- __set_sdk_env(menu_info, (char *)str_array[i]);
- }
- }
- } else {
- str = bundle_get_val(kb, AUL_K_SDK);
- if (str != NULL) {
- __set_sdk_env(menu_info, (char *)str);
- }
- }
- if (menu_info->hwacc != NULL) {
- setenv("HWACC", menu_info->hwacc, 1);
- }
-}
-
_static_ int __prepare_exec(const char *pkg_name,
const char *app_path, app_info_from_db * menu_info,
bundle * kb)
_D("fail to set privileges - check your package's credential\n");
return -1;
}
+
/* SET DUMPABLE - for coredump*/
prctl(PR_SET_DUMPABLE, 1);
return ret;
}
-_static_ char **__create_argc_argv(bundle * kb, int *margc)
-{
- char **argv;
- int argc;
-
- argc = bundle_export_to_argv(kb, &argv);
-
- *margc = argc;
- return argv;
-}
-
_static_ int __normal_fork_exec(int argc, char **argv)
{
_D("start real fork and exec\n");
__normal_fork_exec(app_argc, app_argv);
}
-/*
- * Parsing original app path to retrieve default bundle
- *
- * -1 : Invalid sequence
- * -2 : Buffer overflow
- *
- */
-static inline int __parser(const char *arg, char *out, int out_size)
-{
- register int i;
- int state = 1;
- char *start_out = out;
-
- if (arg == NULL || out == NULL) {
- /* Handles null buffer*/
- return 0;
- }
-
- for (i = 0; out_size > 1; i++) {
- switch (state) {
- case 1:
- switch (arg[i]) {
- case ' ':
- case '\t':
- state = 5;
- break;
- case '\0':
- state = 7;
- break;
- case '\"':
- state = 2;
- break;
- case '\\':
- state = 4;
- break;
- default:
- *out = arg[i];
- out++;
- out_size--;
- break;
- }
- break;
- case 2: /* escape start*/
- switch (arg[i]) {
- case '\0':
- state = 6;
- break;
- case '\"':
- state = 1;
- break;
- default:
- *out = arg[i];
- out++;
- out_size--;
- break;
- }
- break;
- case 4: /* character escape*/
- if (arg[i] == '\0') {
- state = 6;
- } else {
- *out = arg[i];
- out++;
- out_size--;
- state = 1;
- }
- break;
- case 5: /* token*/
- if (out != start_out) {
- *out = '\0';
- out_size--;
- return i;
- }
- i--;
- state = 1;
- break;
- case 6:
- return -1; /* error*/
- case 7: /* terminate*/
- *out = '\0';
- out_size--;
- return 0;
- default:
- state = 6;
- break; /* error*/
- }
- }
-
- if (out_size == 1) {
- *out = '\0';
- }
- /* Buffer overflow*/
- return -2;
-}
-
-_static_ void __modify_bundle(bundle * kb, int caller_pid,
- app_info_from_db * menu_info, int cmd)
+_static_ int __dummy_launch(int dummy_client_fd, app_pkt_t* pkt)
{
- // warning: unused parameter
- (void)caller_pid;
-
- bundle_del(kb, AUL_K_PKG_NAME);
- bundle_del(kb, AUL_K_EXEC);
- bundle_del(kb, AUL_K_PACKAGETYPE);
- bundle_del(kb, AUL_K_HWACC);
-
- /* Parse app_path to retrieve default bundle*/
- if (cmd == APP_START || cmd == APP_START_RES || cmd == APP_OPEN || cmd ==
- APP_RESUME)
- {
- char *ptr;
- char exe[MAX_PATH_LEN];
- int flag;
-
- ptr = _get_original_app_path(menu_info);
-
- flag = __parser(ptr, exe, sizeof(exe));
- if (flag > 0) {
- char key[256];
- char value[256];
-
- ptr += flag;
- _D("parsing app_path: EXEC - %s\n", exe);
-
- do {
- flag = __parser(ptr, key, sizeof(key));
- if (flag <= 0) {
- break;
- }
- ptr += flag;
-
- flag = __parser(ptr, value, sizeof(value));
- if (flag < 0) {
- break;
- }
- ptr += flag;
-
- /*bundle_del(kb, key);*/
- bundle_add(kb, key, value);
- } while (flag > 0);
- } else if (flag == 0) {
- _D("parsing app_path: No arguments\n");
- } else {
- _D("parsing app_path: Invalid argument\n");
- }
- }
+ return __send_pkt_raw_data(dummy_client_fd, pkt);
}
_static_ int __child_raise_win_by_x(int pid, void *priv)
return;
}
-static app_info_from_db *_get_app_info_from_bundle_by_pkgname(
- const char *pkgname, bundle *kb)
+_static_ void __launchpad_exec_dummy(int main_fd, int pool_fd, int client_fd)
{
- app_info_from_db *menu_info;
+ int pid;
- menu_info = calloc(1, sizeof(app_info_from_db));
- if (menu_info == NULL) {
- return NULL;
- }
+ last_dummy_exec_time = time(NULL);
- menu_info->pkg_name = strdup(pkgname);
- menu_info->app_path = strdup(bundle_get_val(kb, AUL_K_EXEC));
- if (menu_info->app_path != NULL) {
- menu_info->original_app_path = strdup(menu_info->app_path);
- }
- menu_info->pkg_type = strdup(bundle_get_val(kb, AUL_K_PACKAGETYPE));
- menu_info->hwacc = strdup(bundle_get_val(kb, AUL_K_HWACC));
+ pid = fork();
- if (!_get_app_path(menu_info)) {
- _free_app_info_from_db(menu_info);
- return NULL;
- }
+ if (pid == 0) // child
+ {
+ setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
+ _D("Launch dummy process...");
+
+ //temp - this requires some optimization.
+ sleep(1);
+ _D("sleeping 1sec...");
+
+ /* Set new session ID & new process group ID*/
+ /* In linux, child can set new session ID without check permission */
+ /* TODO : should be add to check permission in the kernel*/
+ setsid();
+
+ /* SET OOM*/
+ __set_oom();
+
+
+ if (main_fd != -1)
+ {
+ close(main_fd);
+ }
+
+ if (pool_fd != -1)
+ {
+ close(pool_fd);
+ }
+
+ if (client_fd != -1)
+ {
+ close(client_fd);
+ }
+
+ __signal_unset_sigchld();
+ __signal_fini();
+
+ /* SET DUMPABLE - for coredump*/
+ prctl(PR_SET_DUMPABLE, 1);
+
+ {
+ void *handle = NULL;
+ int (*dl_main) (int, char **);
+
+ handle = dlopen(WRT_CLIENT_PATH, RTLD_NOW | RTLD_GLOBAL);
+
+ if (handle == NULL)
+ {
+ _E("dlopen failed.");
+ exit(-1);
+ }
+
+ dl_main = dlsym(handle, "main");
+
+ sprintf(g_argv[1], "%s", "-d");
+
+ if (dl_main != NULL)
+ {
+ dl_main(g_argc, g_argv);
+ }
+ else
+ {
+ _E("dlsym not founded. bad preloaded app - check fpie pie");
+ }
- return menu_info;
+ exit(0);
+ }
+ }
}
-_static_ void __launchpad_main_loop(int main_fd)
+_static_ void __launchpad_main_loop(int main_fd, int pool_fd)
{
bundle *kb = NULL;
app_pkt_t *pkt = NULL;
PERF("get package information & modify bundle done");
+ if (dummy_process_pid != DUMMY_NONE)
+ {
+ snprintf(sock_path, UNIX_PATH_MAX, "%s/%d", AUL_SOCK_PREFIX, dummy_process_pid);
+ unlink(sock_path);
+
+ __dummy_launch(dummy_process_fd, pkt);
+
+ pid = dummy_process_pid;
+ is_real_launch = 1;
+ close(dummy_process_fd);
+
+ dummy_process_pid = DUMMY_NONE;
+ dummy_process_fd = -1;
+
+ /* Temporary log: launch time checking */
+ LOG(LOG_DEBUG, "LAUNCH", "[%s:Platform:launchpad:done]", app_path);
+
+ __launchpad_exec_dummy(main_fd, pool_fd, clifd);
+
+ _D("==> dummy launch pid : %d %s\n", pid, app_path);
+ }
+ else
{
pid = fork();
- if (pid == 0) {
+
+ if (pid == 0)
+ {
PERF("fork done");
_E("lock up test log(no error) : fork done");
int main(int argc, char **argv)
{
- int main_fd;
+ enum {
+ LAUNCH_PAD = 0,
+ POOL_SERVER,
+ DUMMY_PROCESS,
+ POLLFD_MAX
+ };
+
+ int main_fd = -1, pool_fd = -1;
struct pollfd pfds[POLLFD_MAX];
- int i;
+
+ memset(pfds, 0x00, sizeof(pfds));
+
+ // process pool feature disable
+ if (getenv("WRT_PROCESS_POOL_DISABLE"))
+ {
+ process_pool_disable = 1;
+ }
/* init without concerning X & EFL*/
main_fd = __launchpad_pre_init(argc, argv);
- if (main_fd < 0) {
+
+ if (main_fd < 0)
+ {
_E("launchpad pre init failed");
- exit(-1);
+ goto exit_main;
+ }
+
+ pfds[LAUNCH_PAD].fd = main_fd;
+ pfds[LAUNCH_PAD].events = POLLIN;
+ pfds[LAUNCH_PAD].revents = 0;
+
+ pool_fd = __create_process_pool_server();
+
+ if (pool_fd == -1)
+ {
+ _E("Error creationg pool server!");
+ goto exit_main;
}
- pfds[0].fd = main_fd;
- pfds[0].events = POLLIN;
- pfds[0].revents = 0;
+ pfds[POOL_SERVER].fd = pool_fd;
+ pfds[POOL_SERVER].events = POLLIN;
+ pfds[POOL_SERVER].revents = 0;
- while (1) {
- if (poll(pfds, POLLFD_MAX, -1) < 0) {
+ while (1)
+ {
+ if (dummy_process_pid == DUMMY_NONE)
+ {
+ pfds[DUMMY_PROCESS].fd = -1;
+ pfds[DUMMY_PROCESS].events = 0;
+ pfds[DUMMY_PROCESS].revents = 0;
+
+ if ( !process_pool_disable &&
+ DIFF(last_dummy_exec_time, time(NULL)) > EXEC_DUMMY_EXPIRED)
+ {
+ __launchpad_exec_dummy(main_fd, pool_fd, -1);
+ }
+ }
+
+ if (poll(pfds, POLLFD_MAX, -1) < 0)
+ {
continue;
}
+ _D("pfds[LAUNCH_PAD].revents : 0x%x", pfds[LAUNCH_PAD].revents) ;
+ _D("pfds[POOL_SERVER].revents : 0x%x", pfds[POOL_SERVER].revents) ;
+ _D("pfds[DUMMY_PROCESS].revents : 0x%x", pfds[DUMMY_PROCESS].revents) ;
+
/* init with concerning X & EFL (because of booting
- * sequence problem)*/
- if (__launchpad_post_init() < 0) {
+ * sequence problem)*/
+ if (__launchpad_post_init() < 0)
+ {
_E("launcpad post init failed");
- exit(-1);
+ goto exit_main;
+ }
+
+ if ((pfds[LAUNCH_PAD].revents & POLLIN) != 0)
+ {
+ _D("pfds[LAUNCH_PAD].revents & POLLIN");
+ __launchpad_main_loop(pfds[LAUNCH_PAD].fd, pfds[POOL_SERVER].fd);
}
- for (i = 0; i < POLLFD_MAX; i++) {
- if ((pfds[i].revents & POLLIN) != 0) {
- __launchpad_main_loop(pfds[i].fd);
+ if ((pfds[POOL_SERVER].revents & POLLIN) != 0)
+ {
+ int server_fd, client_fd, client_pid;
+
+ server_fd = pfds[POOL_SERVER].fd;
+
+ _D("pfds[POOL_SERVER].revents & POLLIN");
+
+ if (dummy_process_pid == DUMMY_NONE)
+ {
+ __accept_dummy_process(server_fd, &client_fd, &client_pid);
+
+ dummy_process_pid = client_pid;
+ dummy_process_fd = client_fd;
+
+ pfds[DUMMY_PROCESS].fd = dummy_process_fd;
+ pfds[DUMMY_PROCESS].events = POLLIN|POLLHUP;
+ pfds[DUMMY_PROCESS].revents = 0;
+
+ _D("Dummy process was connected! (pid:%d)", dummy_process_pid);
+ }
+ else
+ {
+ __refuse_dummy_process(server_fd);
+
+ _E("Refused dummy process connection!");
}
}
+
+ if ((pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL)) != 0)
+ {
+ _D("pfds[DUMMY_PROCESS].revents & (POLLHUP|POLLNVAL) (pid:%d)", dummy_process_pid);
+ close(pfds[DUMMY_PROCESS].fd);
+
+ dummy_process_pid = DUMMY_NONE;
+ dummy_process_fd = -1;
+
+ pfds[DUMMY_PROCESS].fd = -1;
+ pfds[DUMMY_PROCESS].events = 0;
+ pfds[DUMMY_PROCESS].revents = 0;
+ }
}
+
+ return 0;
+
+ exit_main:
+ if (main_fd != -1)
+ {
+ close(main_fd);
+ }
+
+ if (pool_fd != -1)
+ {
+ close(pool_fd);
+ }
+
+ return -1;
}