[Release] wrt_0.8.166 for tizen_2.1 branch
[platform/framework/web/wrt.git] / src / wrt-launchpad-daemon / launchpad_src / launchpad.c
index 415519e..1dcab54 100644 (file)
@@ -30,6 +30,8 @@
 #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);
@@ -77,9 +84,7 @@ _static_ int __fake_launch_app(int cmd, int pid, 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);
@@ -87,91 +92,13 @@ _static_ int __term_app(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)
@@ -198,6 +125,7 @@ _static_ int __prepare_exec(const char *pkg_name,
         _D("fail to set privileges - check your package's credential\n");
         return -1;
     }
+
     /* SET DUMPABLE - for coredump*/
     prctl(PR_SET_DUMPABLE, 1);
 
@@ -235,17 +163,6 @@ _static_ int __fake_launch_app(int cmd, int pid, bundle * kb)
     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");
@@ -299,152 +216,9 @@ _static_ void __real_launch(const char *app_path, bundle * kb)
     __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)
@@ -646,33 +420,84 @@ _static_ void __send_result_to_caller(int clifd, int ret)
     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;
@@ -726,9 +551,33 @@ _static_ void __launchpad_main_loop(int main_fd)
 
     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");
 
@@ -846,38 +695,143 @@ _static_ int __launchpad_post_init()
 
 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;
 }