Introduce new API for hydra mode: 61/212861/6
authorGleb Balykov <g.balykov@samsung.com>
Tue, 19 Feb 2019 14:09:18 +0000 (17:09 +0300)
committerKonstantin Baladurin <k.baladurin@samsung.com>
Tue, 17 Sep 2019 07:32:40 +0000 (10:32 +0300)
typedef void (*hydra_precreate_cb)(void *user_data);
typedef void (*hydra_create_cb)(void *user_data);
typedef void (*hydra_fork_cb)(void *user_data);
typedef int (*hydra_terminate_cb)(void *user_data);

typedef struct {
        hydra_precreate_cb precreate;
hydra_create_cb create;
hydra_fork_cb fork;
hydra_terminate_cb terminate;
} hydra_lifecycle_callback_s;

int launchpad_hydra_main(int argc, char **argv,
hydra_lifecycle_callback_s *hydra_callbacks,
loader_lifecycle_callback_s *callbacks,
loader_adapter_s *adapter, void *user_data);

In this mode candidates fork from one "hydra" candidate
that allows to share memory between them:

     Launchpad
 |
 | (fork initial loader in hydra mode)
                 |
 +----+
      |
   loader (hydra-mode)
      |
      | launchpad_hydra_main
      |
      | precreate (hydra callback)
      |
      | (decide run in hydra mode or call launchpad_loader_main)
      |
      | create (hydra callback)
      |
      | (initial hydra fork)
                      |
      +-------+-------+ <- initial candidate
      |               |
              |               | fork (hydra callback)
              |               |
      |               | launchpad_loader_main
      |               |
      |      (loader event loop)
      |
      |
      | _connect_to_launchpad_hydra
      |
     (hydra event loop) <- waits commands from launchpad
              |
              | (fork on request)
              |
              +-------+ <- new candidate
                      |
                      | fork (hydra callback)
                      |
                      | quit from hydra loop
                      |
                      | terminate (hydra callback)
                      |
                      | launchpad_loader_main
                      |
             (loader event loop)

Change-Id: I68566cb0e45031b9f4f8039ca2f1de09bb6dafe9

inc/launchpad.h
inc/launchpad_common.h
inc/loader_info.h
src/launchpad.c
src/launchpad_common.c
src/launchpad_lib.c
src/launchpad_signal.c
src/loader_info.c

index b5a11db03b883815d38cc0f995339e9ed49440e6..0dfea814146aff69efe50df240f876762fc33a0a 100644 (file)
@@ -29,6 +29,11 @@ typedef int (*loader_launch_cb)(int argc, char **argv, const char *app_path,
                void *user_data);
 typedef int (*loader_terminate_cb)(int argc, char **argv, void *user_data);
 
+typedef void (*hydra_precreate_cb)(void *user_data);
+typedef void (*hydra_create_cb)(void *user_data);
+typedef void (*hydra_fork_cb)(void *user_data);
+typedef int (*hydra_terminate_cb)(void *user_data);
+
 typedef void (*loader_receiver_cb)(int fd);
 typedef void (*loader_loop_begin_cb)(void *user_data);
 typedef void (*loader_loop_quit_cb)(void *user_data);
@@ -42,6 +47,13 @@ typedef struct {
        loader_terminate_cb terminate;
 } loader_lifecycle_callback_s;
 
+typedef struct {
+       hydra_precreate_cb precreate;
+       hydra_create_cb create;
+       hydra_fork_cb fork;
+       hydra_terminate_cb terminate;
+} hydra_lifecycle_callback_s;
+
 typedef struct {
        loader_loop_begin_cb loop_begin;
        loader_loop_quit_cb loop_quit;
@@ -60,6 +72,11 @@ int launchpad_loader_main(int argc, char **argv,
                loader_lifecycle_callback_s *callbacks,
                loader_adapter_s *adapter, void *user_data);
 
+int launchpad_hydra_main(int argc, char **argv,
+               hydra_lifecycle_callback_s *hydra_callbacks,
+               loader_lifecycle_callback_s *callbacks,
+               loader_adapter_s *adapter, void *user_data);
+
 /*
  * @par Description
  *      Set program scheduling priority.
index b6aa841f1550f039542af357776dd8bb60c25b29..0ebb4524545cb6260abdb4ad1814e979ab172333 100644 (file)
@@ -35,6 +35,7 @@
 
 #define SOCKET_PATH "/run/aul"
 #define LAUNCHPAD_LOADER_SOCKET_NAME ".launchpad-type"
+#define HYDRA_LOADER_SOCKET_NAME ".hydra-loader"
 #define MAX_PENDING_CONNECTIONS 10
 #define MAX_LOCAL_BUFSZ 128
 #define AUL_SOCK_MAXBUFF 131071
@@ -77,10 +78,15 @@ enum loader_arg {
        LOADER_ARG_PATH,
        LOADER_ARG_TYPE,
        LOADER_ARG_ID,
+       LOADER_ARG_HYDRA,
        LOADER_ARG_EXTRA,
        LOADER_ARG_DUMMY,
 };
 
+enum hydra_cmd {
+       LAUNCH_CANDIDATE,
+};
+
 typedef struct _app_pkt_t {
        int cmd;
        int len;
@@ -113,6 +119,7 @@ app_pkt_t *_recv_pkt_raw(int fd);
 app_pkt_t *_accept_recv_pkt_raw(int fd, int *clifd, struct ucred *cr);
 int _send_pkt_raw(int client_fd, app_pkt_t *pkt);
 int  _connect_to_launchpad(int type, int id);
+int _connect_to_launchpad_hydra(int type, int id);
 int _set_sock_option(int fd, int cli);
 void _set_env(appinfo_t *menu_info, bundle *kb);
 char **_create_argc_argv(bundle *kb, int *margc);
index 224510787e5bfcec2443f6727ba2961114f995c9..871419815ff9a87f005181bae412cf84c6db32de 100644 (file)
@@ -52,6 +52,7 @@ typedef struct _loader_info {
        int activation_method;
        int deactivation_method;
        unsigned int ttl;
+       bool is_hydra;
 } loader_info_t;
 
 typedef void (*loader_info_foreach_cb)(loader_info_t *info, void *data);
index c5d097f910927c5c237266b3f72d790841ac71d2..75d6331d0e1dfc7c9777e0bea689e8f30351b299 100755 (executable)
@@ -52,6 +52,7 @@
 #define EXEC_CANDIDATE_WAIT 1
 #define DIFF(a, b) (((a) > (b)) ? (a) - (b) : (b) - (a))
 #define CANDIDATE_NONE 0
+#define HYDRA_NONE 0
 #define PROCESS_POOL_LAUNCHPAD_SOCK ".launchpad-process-pool-sock"
 #define LAUNCHPAD_LOGGER_SOCK ".launchpad-logger-sock"
 #define LOADER_PATH_DEFAULT "/usr/bin/launchpad-loader"
@@ -73,10 +74,13 @@ enum candidate_process_state_e {
 typedef struct {
        int type;
        bool prepared;
-       int pid;
+       int pid; /* for hydra this pid is not the pid of hydra itself */
+                /* but pid of non-hydra candidate, which was forked from hydra */
+       int hydra_pid;
        int loader_id;
        int caller_pid;
        int send_fd;
+       int hydra_fd;
        int last_exec_time;
        guint source;
        guint timer;
@@ -98,6 +102,7 @@ typedef struct {
        unsigned int ttl;
        guint live_timer;
        int state;
+       bool is_hydra;
 } candidate_process_context_t;
 
 typedef struct {
@@ -145,7 +150,7 @@ static candidate_process_context_t *__add_slot(int type, int loader_id,
                int detection_method, int activation_method,
                int deactivation_method, unsigned int ttl, int timeout_val,
                int threshold_max, int threshold_min, bool on_boot,
-               bool app_exists);
+               bool app_exists, bool is_hydra);
 static int __remove_slot(int type, int loader_id);
 static int __add_default_slots(void);
 static gboolean __handle_idle_checker(gpointer data);
@@ -342,6 +347,22 @@ static candidate_process_context_t *__find_slot_from_pid(int pid)
        return NULL;
 }
 
+static candidate_process_context_t *__find_hydra_slot_from_pid(int pid)
+{
+       candidate_process_context_t *cpc;
+       GList *iter = candidate_slot_list;
+
+       while (iter) {
+               cpc = (candidate_process_context_t *)iter->data;
+               if (cpc->is_hydra && pid == cpc->hydra_pid)
+                       return cpc;
+
+               iter = g_list_next(iter);
+       }
+
+       return NULL;
+}
+
 static candidate_process_context_t *__find_slot_from_caller_pid(int caller_pid)
 {
        candidate_process_context_t *cpc;
@@ -457,34 +478,24 @@ error:
        return -1;
 }
 
-static int __listen_candidate_process(int type, int loader_id)
+static int __listen_addr(struct sockaddr_un *addr)
 {
-       struct sockaddr_un addr;
        int fd = -1;
-
-       _D("[launchpad] enter, type: %d", type);
-
-       memset(&addr, 0x00, sizeof(struct sockaddr_un));
-       addr.sun_family = AF_UNIX;
-       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
-                       SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME,
-                       type, loader_id);
-
        fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
        if (fd < 0) {
                _E("Socket error");
                goto error;
        }
 
-       unlink(addr.sun_path);
+       unlink(addr->sun_path);
 
-       _D("bind to %s", addr.sun_path);
-       if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+       _D("bind to %s", addr->sun_path);
+       if (bind(fd, (struct sockaddr *)addr, sizeof(struct sockaddr_un)) < 0) {
                _E("bind error");
                goto error;
        }
 
-       _D("listen to %s", addr.sun_path);
+       _D("listen to %s", addr->sun_path);
        if (listen(fd, MAX_PENDING_CONNECTIONS) == -1) {
                _E("listen error");
                goto error;
@@ -500,6 +511,36 @@ error:
        return -1;
 }
 
+static int __listen_candidate_process(int type, int loader_id)
+{
+       struct sockaddr_un addr;
+
+       _D("[launchpad] enter, type: %d", type);
+
+       memset(&addr, 0x00, sizeof(struct sockaddr_un));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
+                       SOCKET_PATH, getuid(), LAUNCHPAD_LOADER_SOCKET_NAME,
+                       type, loader_id);
+
+       return __listen_addr(&addr);
+}
+
+static int __listen_hydra_process(int type, int loader_id)
+{
+       struct sockaddr_un addr;
+
+       _D("[launchpad] enter, type: %d", type);
+
+       memset(&addr, 0x00, sizeof(struct sockaddr_un));
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/daemons/%d/%s%d-%d",
+                       SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
+                       type, loader_id);
+
+       return __listen_addr(&addr);
+}
+
 static int __get_loader_id(bundle *kb)
 {
        const char *val;
@@ -620,18 +661,49 @@ static void __set_live_timer(candidate_process_context_t *cpc)
        }
 }
 
+static int __hydra_send_request(int fd, enum hydra_cmd cmd)
+{
+       int sent = 0;
+       int size = sizeof(cmd);
+       int send_ret = 0;
+
+       while (sent != size) {
+               send_ret = send(fd, (char *)&cmd + sent,
+                               size - sent, MSG_NOSIGNAL);
+               if (send_ret == -1) {
+                       _E("send error! (%d)", errno);
+                       return -1;
+               }
+
+               sent += send_ret;
+               _D("send(%d: ret: %d) : %d / %d",
+                       fd, send_ret, sent, size);
+       }
+
+       return 0;
+}
+
+static int __hydra_send_launch_candidate_request(int fd)
+{
+       SECURE_LOGD("Send launch cmd to hydra, fd: %d", fd);
+       return __hydra_send_request(fd, LAUNCH_CANDIDATE);
+}
+
 static int __prepare_candidate_process(int type, int loader_id)
 {
        int pid;
        char type_str[2] = {0, };
        char loader_id_str[10] = {0, };
        char argbuf[LOADER_ARG_LEN];
-       char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL};
+       char *argv[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
        candidate_process_context_t *cpt = __find_slot(type, loader_id);
 
        if (cpt == NULL)
                return -1;
 
+       if (cpt->is_hydra && cpt->hydra_pid != HYDRA_NONE)
+               return __hydra_send_launch_candidate_request(cpt->hydra_fd);
+
        _D("prepare candidate process / type:%d", type);
        memset(argbuf, ' ', LOADER_ARG_LEN);
        argbuf[LOADER_ARG_LEN - 1] = '\0';
@@ -644,6 +716,7 @@ static int __prepare_candidate_process(int type, int loader_id)
        argv[LOADER_ARG_PATH] = cpt->loader_path;
        argv[LOADER_ARG_TYPE] = type_str;
        argv[LOADER_ARG_ID] = loader_id_str;
+       argv[LOADER_ARG_HYDRA] = cpt->is_hydra ? "1" : "0";
        argv[LOADER_ARG_EXTRA] = cpt->loader_extra;
 
        pid = __fork_app_process(__exec_loader_process, argv);
@@ -652,8 +725,12 @@ static int __prepare_candidate_process(int type, int loader_id)
                return -1;
        }
 
-       cpt->pid = pid;
-       __set_live_timer(cpt);
+       if (cpt->is_hydra) {
+               cpt->hydra_pid = pid;
+       } else {
+               cpt->pid = pid;
+               __set_live_timer(cpt);
+       }
 
        return 0;
 }
@@ -721,6 +798,26 @@ static void __dispose_candidate_process(candidate_process_context_t *cpc)
        __reset_slot(cpc);
 }
 
+static void __dispose_hydra_process(candidate_process_context_t *cpc)
+{
+       if (!cpc)
+               return;
+
+       __dispose_candidate_process(cpc);
+
+       _D("Dispose hydra process %d", cpc->type);
+       if (cpc->hydra_pid > 0) {
+               _D("kill process %d", cpc->hydra_pid);
+               __kill_process(cpc->hydra_pid);
+               cpc->hydra_pid = HYDRA_NONE;
+       }
+
+       if (cpc->hydra_fd > 0) {
+               close(cpc->hydra_fd);
+               cpc->hydra_fd = -1;
+       }
+}
+
 static int __send_launchpad_loader(candidate_process_context_t *cpc,
                app_pkt_t *pkt, const char *app_path, int clifd)
 {
@@ -1230,6 +1327,30 @@ static gboolean __handle_loader_client_event(gpointer data)
        return G_SOURCE_CONTINUE;
 }
 
+static gboolean __handle_hydra_client_event(gpointer data)
+{
+       loader_context_t *lc = (loader_context_t *)data;
+       int type = lc->type;
+       int loader_id = lc->loader_id;
+       gushort revents = lc->gpollfd->revents;
+       candidate_process_context_t *cpc = __find_slot(type, loader_id);
+
+       if (cpc == NULL)
+               return G_SOURCE_REMOVE;
+
+       if (revents & (G_IO_HUP | G_IO_NVAL)) {
+               SECURE_LOGE("Type %d hydra process was " \
+                               "(POLLHUP|POLLNVAL), pid: %d",
+                               cpc->type, cpc->hydra_pid);
+               cpc->hydra_pid = HYDRA_NONE;
+               __dispose_hydra_process(cpc);
+               __prepare_candidate_process(cpc->type, cpc->loader_id);
+               return G_SOURCE_REMOVE;
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
 static gboolean __handle_loader_event(gpointer data)
 {
        loader_context_t *lc = (loader_context_t *) data;
@@ -1248,6 +1369,11 @@ static gboolean __handle_loader_event(gpointer data)
        if (!cpc->prepared) {
                ret = __accept_candidate_process(fd, &client_fd, &client_pid);
                if (ret >= 0) {
+                       /* for hydra need to set pid to pid of non-hydra candidate, */
+                       /* which is connecting now */
+                       if (cpc->is_hydra)
+                               cpc->pid = client_pid;
+
                        cpc->prepared = true;
                        cpc->send_fd = client_fd;
 
@@ -1267,6 +1393,43 @@ static gboolean __handle_loader_event(gpointer data)
        return G_SOURCE_CONTINUE;
 }
 
+static gboolean __handle_hydra_event(gpointer data)
+{
+       loader_context_t *lc = (loader_context_t *) data;
+       int fd = lc->gpollfd->fd;
+       int type = lc->type;
+       int loader_id = lc->loader_id;
+       int client_fd;
+       int client_pid;
+       int ret;
+
+       candidate_process_context_t *cpc = __find_slot(type, loader_id);
+
+       if (cpc == NULL)
+               return G_SOURCE_REMOVE;
+
+       if (!cpc->prepared) {
+               ret = __accept_candidate_process(fd, &client_fd, &client_pid);
+               if (ret >= 0) {
+                       cpc->hydra_fd = client_fd;
+
+                       SECURE_LOGD("Type %d hydra process was connected," \
+                                       " pid: %d", type, cpc->hydra_pid);
+
+                       cpc->source = __poll_fd(client_fd, G_IO_IN | G_IO_HUP,
+                                       __handle_hydra_client_event, type,
+                                       loader_id);
+                       if (cpc->source == 0)
+                               close(client_fd);
+               }
+       } else {
+               __refuse_candidate_process(fd);
+               _E("Refused hydra process connection");
+       }
+
+       return G_SOURCE_CONTINUE;
+}
+
 static gboolean __handle_sigchild(gpointer data)
 {
        candidate_process_context_t *cpc;
@@ -1275,6 +1438,7 @@ static gboolean __handle_sigchild(gpointer data)
        struct signalfd_siginfo siginfo;
        ssize_t s;
        char *appid;
+       int pid;
 
        do {
                s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
@@ -1286,25 +1450,34 @@ static gboolean __handle_sigchild(gpointer data)
 
                _signal_process_sigchld(&siginfo);
 
+               pid = siginfo.ssi_code != SI_QUEUE ? siginfo.ssi_pid : siginfo.ssi_int;
+
                appid = g_hash_table_lookup(__pid_table,
-                               GINT_TO_POINTER(siginfo.ssi_pid));
+                               GINT_TO_POINTER(pid));
                if (appid) {
-                       security_manager_cleanup_app(appid, siginfo.ssi_uid, siginfo.ssi_pid);
+                       security_manager_cleanup_app(appid, siginfo.ssi_uid, pid);
                        g_hash_table_remove(__pid_table,
-                                       GINT_TO_POINTER(siginfo.ssi_pid));
+                                       GINT_TO_POINTER(pid));
                }
 
-               cpc = __find_slot_from_pid(siginfo.ssi_pid);
+               cpc = __find_slot_from_pid(pid);
                if (cpc != NULL) {
                        cpc->pid = CANDIDATE_NONE;
                        __dispose_candidate_process(cpc);
                        __prepare_candidate_process(cpc->type, cpc->loader_id);
+               } else {
+                       cpc = __find_hydra_slot_from_pid(pid);
+                       if (cpc != NULL) {
+                               cpc->hydra_pid = HYDRA_NONE;
+                               __dispose_hydra_process(cpc);
+                               __prepare_candidate_process(cpc->type, cpc->loader_id);
+                       }
                }
 
-               cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
+               cpc = __find_slot_from_caller_pid(pid);
                while (cpc) {
                        __remove_slot(LAUNCHPAD_TYPE_DYNAMIC, cpc->loader_id);
-                       cpc = __find_slot_from_caller_pid(siginfo.ssi_pid);
+                       cpc = __find_slot_from_caller_pid(pid);
                }
        } while (s > 0);
 
@@ -1498,7 +1671,7 @@ static int __dispatch_cmd_add_loader(bundle *kb)
                                DEFAULT_CPU_THRESHOLD_MAX,
                                DEFAULT_CPU_THRESHOLD_MIN,
                                false,
-                               true);
+                               true, 0);
                __set_timer(cpc);
                return lid;
        }
@@ -1886,7 +2059,7 @@ static candidate_process_context_t *__add_slot(int type, int loader_id,
                int activation_method, int deactivation_method,
                unsigned int ttl, int timeout_val,
                int threshold_max, int threshold_min,
-               bool on_boot, bool app_exists)
+               bool on_boot, bool app_exists, bool is_hydra)
 {
        candidate_process_context_t *cpc;
        int fd = -1;
@@ -1903,9 +2076,11 @@ static candidate_process_context_t *__add_slot(int type, int loader_id,
        cpc->type = type;
        cpc->prepared = false;
        cpc->pid = CANDIDATE_NONE;
+       cpc->hydra_pid = HYDRA_NONE;
        cpc->caller_pid = caller_pid;
        cpc->loader_id = loader_id;
        cpc->send_fd = -1;
+       cpc->hydra_fd = -1;
        cpc->last_exec_time = 0;
        cpc->source = 0;
        cpc->timer = 0;
@@ -1926,6 +2101,7 @@ static candidate_process_context_t *__add_slot(int type, int loader_id,
        cpc->deactivation_method = deactivation_method;
        cpc->ttl = ttl;
        cpc->live_timer = 0;
+       cpc->is_hydra = is_hydra;
 
        if ((cpc->deactivation_method & METHOD_OUT_OF_MEMORY) &&
                        __is_low_memory())
@@ -1950,6 +2126,25 @@ static candidate_process_context_t *__add_slot(int type, int loader_id,
                return NULL;
        }
 
+       if (is_hydra) {
+               fd = __listen_hydra_process(cpc->type, cpc->loader_id);
+               if (fd == -1) {
+                       _E("[launchpad] Listening the socket to " \
+                                       "the type %d hydra process failed.",
+                                       cpc->type);
+                       free(cpc);
+                       return NULL;
+               }
+
+               pollfd = __poll_fd(fd, G_IO_IN, (GSourceFunc)__handle_hydra_event,
+                       cpc->type, cpc->loader_id);
+               if (pollfd == 0) {
+                       close(fd);
+                       free(cpc);
+                       return NULL;
+               }
+       }
+
        candidate_slot_list = g_list_append(candidate_slot_list, cpc);
 
        return cpc;
@@ -2122,7 +2317,7 @@ static void __add_slot_from_info(gpointer data, gpointer user_data)
                                info->cpu_threshold_max,
                                info->cpu_threshold_min,
                                false,
-                               info->app_exists);
+                               info->app_exists, info->is_hydra);
                if (cpc == NULL)
                        return;
 
@@ -2149,7 +2344,7 @@ static void __add_slot_from_info(gpointer data, gpointer user_data)
                                info->cpu_threshold_max,
                                info->cpu_threshold_min,
                                info->on_boot,
-                               info->app_exists);
+                               info->app_exists, info->is_hydra);
                if (cpc == NULL)
                        return;
 
index 13055e20b866f20e54f0cf7de71432c67cccb527..eade9b555ce5a4f8ce73f9ea1d2177b116581182 100644 (file)
@@ -708,6 +708,36 @@ int _connect_to_launchpad(int type, int id)
        return fd;
 }
 
+int _connect_to_launchpad_hydra(int type, int id)
+{
+       char path[PATH_MAX];
+       int fd;
+       int send_ret;
+       pid_t client_pid;
+
+
+       _D("[hydra] enter, type: %d", type);
+
+       snprintf(path, sizeof(path), "%s/daemons/%d/%s%d-%d",
+                       SOCKET_PATH, getuid(), HYDRA_LOADER_SOCKET_NAME,
+                       type, id);
+       fd = __create_client_socket(path);
+       if (fd < 0)
+               return -1;
+
+       client_pid = getpid();
+       send_ret = send(fd, &client_pid, sizeof(client_pid), MSG_NOSIGNAL);
+       _D("send(%d) : %d", client_pid, send_ret);
+       if (send_ret == -1) {
+               _E("send error");
+               close(fd);
+               return -1;
+       }
+
+       SECURE_LOGD("[hydra] done, connect fd: %d", fd);
+       return fd;
+}
+
 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
 static void __set_execution_domain(void)
 {
index 4041141dff229305553138be090ef174015e8fb7..ab243f1f62908d1ebc04b15736ee6cad0d05f081 100644 (file)
 #include <buxton2.h>
 #include <vconf.h>
 
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
 #include "launchpad_common.h"
 #include "launchpad.h"
 #include "preexec.h"
@@ -39,6 +43,7 @@
 
 #define AUL_PR_NAME 16
 
+static hydra_lifecycle_callback_s *__hydra_callbacks;
 static loader_lifecycle_callback_s *__loader_callbacks;
 static loader_adapter_s *__loader_adapter;
 static void *__loader_user_data;
@@ -47,6 +52,8 @@ static char **__argv;
 static bundle *__bundle;
 static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
 static int __loader_id;
+static pid_t __candidate_pid = -1;
+static struct sigaction __prev_sigchld;
 
 static void __at_exit_to_release_bundle(void)
 {
@@ -305,6 +312,82 @@ static void __receiver_cb(int fd)
        }
 }
 
+static void __hydra_receiver_cb(int fd)
+{
+       char err_str[MAX_LOCAL_BUFSZ] = { 0, };
+       enum hydra_cmd cmd = -1;
+       int len;
+       pid_t pid;
+       int r;
+
+       _D("[hydra] ECORE_FD_READ");
+
+retry_recv:
+       len = recv(fd, &cmd, sizeof(cmd), MSG_WAITALL);
+       if (len < 0)
+               if (errno == EINTR)
+                       goto retry_recv;
+
+       if (len < sizeof(cmd)) {
+               _E("[hydra] failed to recv: %s",
+                       strerror_r(errno, err_str, sizeof(err_str)));
+               goto err;
+       }
+
+       _D("[hydra] success recv cmd: %d", cmd);
+
+       switch (cmd) {
+       case LAUNCH_CANDIDATE:
+               _D("[hydra] launch new child");
+               break;
+       default:
+               _E("[hydra] unknown command from launchpad: %d", cmd);
+               goto err;
+       }
+
+       pid = fork();
+       if (pid < 0) {
+               _E("[hydra] unable to fork: %s",
+                       strerror_r(errno, err_str, sizeof(err_str)));
+       } else if (pid > 0) {
+               SECURE_LOGD("[hydra] forked candidate with pid=%d", pid);
+
+               __candidate_pid = pid;
+
+               return;
+       } else {
+               if (sigaction(SIGCHLD, &__prev_sigchld, NULL)) {
+                       _E("[hydra] sigaction failed: %s",
+                               strerror_r(errno, err_str, sizeof(err_str)));
+                       exit(-1);
+               }
+
+               if (__hydra_callbacks->fork)
+                       __hydra_callbacks->fork(__loader_user_data);
+
+               /* child, exit loop and start initialization */
+               __loader_adapter->remove_fd(__loader_user_data, fd);
+               close(fd);
+
+               __loader_adapter->loop_quit(__loader_user_data);
+
+               if (__hydra_callbacks->terminate)
+                       __hydra_callbacks->terminate(__loader_user_data);
+
+               r = launchpad_loader_main(__argc, __argv, __loader_callbacks,
+                               __loader_adapter, __loader_user_data);
+               if (r != 0)
+                       _E("[hydra] launchpad_loader_main failed. Error: %d", r);
+
+               exit(r);
+       }
+
+err:
+       __loader_adapter->remove_fd(__loader_user_data, fd);
+       close(fd);
+       exit(-1);
+}
+
 static void __update_lang(keynode_t *node, void *user_data)
 {
        char *lang = vconf_keynode_get_str(node);
@@ -380,15 +463,52 @@ bundle *launchpad_loader_get_bundle()
        return __bundle;
 }
 
+static void sigchld_hdl(int code, siginfo_t *siginfo, void *context)
+{
+       pid_t child_pid;
+       union sigval val;
+       bool is_group_leader = !kill(-siginfo->si_pid, 0);
+
+       while ((child_pid = waitpid(-1, NULL, WNOHANG)) > 0) {
+               /* sigqueue to launchpad getppid() with data=child_pid */
+               if (child_pid == __candidate_pid)
+                       __candidate_pid = -1;
+
+               if (is_group_leader)
+                       kill(-child_pid, SIGKILL);
+
+               val.sival_int = child_pid;
+               sigqueue(getppid(), SIGCHLD, val);
+       }
+
+       if (__prev_sigchld.sa_flags & SA_SIGINFO) {
+               if (__prev_sigchld.sa_sigaction)
+                       __prev_sigchld.sa_sigaction(code, siginfo, context);
+       } else if (__prev_sigchld.sa_handler &&
+                       __prev_sigchld.sa_handler != SIG_IGN &&
+                       __prev_sigchld.sa_handler != SIG_DFL) {
+               __prev_sigchld.sa_handler(code);
+       }
+}
+
 API int launchpad_loader_main(int argc, char **argv,
                loader_lifecycle_callback_s *callbacks,
                loader_adapter_s *adapter, void *user_data)
 {
-       if (argc < 3) {
+       int is_hydra;
+
+       if (argc < 4) {
                _E("too few argument.");
                return -1;
        }
 
+       is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
+
+       if (is_hydra) {
+               _D("Cannot run in hydra mode");
+               return -1;
+       }
+
        __loader_type = argv[LOADER_ARG_TYPE][0] - '0';
        if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
                _E("invalid argument. (type: %d)", __loader_type);
@@ -434,3 +554,131 @@ API int launchpad_loader_set_priority(int prio)
 {
        return _set_priority(prio);
 }
+
+API int launchpad_hydra_main(int argc, char **argv,
+               hydra_lifecycle_callback_s *hydra_callbacks,
+               loader_lifecycle_callback_s *callbacks,
+               loader_adapter_s *adapter, void *user_data)
+{
+       char err_str[MAX_LOCAL_BUFSZ] = { 0, };
+       int is_hydra;
+       int loader_type;
+       int loader_id;
+       int client_fd;
+       pid_t pid;
+       struct sigaction new_act;
+
+       if (argc < 4) {
+               _E("[hydra] too few argument.");
+               return -1;
+       }
+
+       is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
+       argv[LOADER_ARG_HYDRA] = "0";
+       _D("[hydra] mode: %d", is_hydra);
+
+       loader_type = argv[LOADER_ARG_TYPE][0] - '0';
+       if (loader_type < 0 || loader_type >= LAUNCHPAD_TYPE_MAX) {
+               _E("[hydra] invalid argument. (type: %d)", loader_type);
+               return -1;
+       }
+
+       loader_id = atoi(argv[LOADER_ARG_ID]);
+
+       if (hydra_callbacks == NULL) {
+               _E("[hydra] invalid argument. hydra_callback is null");
+               return -1;
+       }
+
+       if (adapter == NULL) {
+               _E("[hydra] invalid argument. adapter is null");
+               return -1;
+       }
+
+       if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
+               || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
+               _E("[hydra] invalid argument. adapter callback is null");
+               return -1;
+       }
+
+       if (hydra_callbacks->precreate)
+               hydra_callbacks->precreate(user_data);
+
+       if (!is_hydra) {
+               _D("Run in non hydra mode");
+               return launchpad_loader_main(argc, argv, callbacks,
+                               adapter, user_data);
+       }
+
+       if (hydra_callbacks->create)
+               hydra_callbacks->create(user_data);
+
+       /* Set sigchld handler after calling create, because it can overwrite */
+       /* our handler */
+       memset(&new_act, 0, sizeof(new_act));
+       new_act.sa_sigaction = sigchld_hdl;
+       new_act.sa_flags |= SA_SIGINFO;
+
+       if (sigaction(SIGCHLD, &new_act, &__prev_sigchld)) {
+               _E("[hydra] sigaction failed: %s",
+                       strerror_r(errno, err_str, sizeof(err_str)));
+               return -1;
+       }
+
+       /* initial fork to prepare first loader */
+       _D("[hydra] initial fork");
+
+       pid = fork();
+       if (pid < 0) {
+               _E("[hydra] unable to fork: %s",
+                       strerror_r(errno, err_str, sizeof(err_str)));
+               return -1;
+       } else if (pid == 0) {
+               if (sigaction(SIGCHLD, &__prev_sigchld, NULL)) {
+                       _E("[hydra] sigaction failed: %s",
+                               strerror_r(errno, err_str, sizeof(err_str)));
+                       return -1;
+               }
+
+               if (hydra_callbacks->fork)
+                       hydra_callbacks->fork(user_data);
+
+               return launchpad_loader_main(argc, argv, callbacks,
+                               adapter, user_data);
+       } else {
+               __hydra_callbacks = hydra_callbacks;
+               __loader_callbacks = callbacks;
+               __loader_adapter = adapter;
+               __loader_user_data = user_data;
+               __candidate_pid = pid;
+               __argc = argc;
+               __argv = argv;
+
+               __preexec_init(argc, argv);
+
+               /* 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();
+
+               malloc_trim(0);
+
+               client_fd = _connect_to_launchpad_hydra(loader_type, loader_id);
+               if (client_fd == -1) {
+                       _D("[hydra] connecting to launchpad process was failed.");
+                       return -1;
+               }
+
+               __loader_adapter->add_fd(__loader_user_data, client_fd,
+                               __hydra_receiver_cb);
+
+               __loader_adapter->loop_begin(__loader_user_data);
+
+               if (__hydra_callbacks->terminate)
+                       return __hydra_callbacks->terminate(__loader_user_data);
+
+               return -1;
+       }
+
+       return 0;
+}
\ No newline at end of file
index deb581ca4c979c74c7129346a654cdf5460808e5..e6a650393edc25168069849b53a8989510bc86fc 100644 (file)
@@ -281,14 +281,20 @@ void _signal_process_sigchld(struct signalfd_siginfo *info)
        pid_t child_pid;
        pid_t child_pgid;
 
-       child_pgid = getpgid(info->ssi_pid);
-       _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
-               child_pgid, info->ssi_signo, info->ssi_status);
-
-       while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
-               if (child_pid == child_pgid)
-                       killpg(child_pgid, SIGKILL);
-               __sigchild_action(child_pid);
+       if (info->ssi_code != SI_QUEUE) {
+               child_pgid = getpgid(info->ssi_pid);
+               _D("dead_pid = %d pgid = %d signo = %d status = %d", info->ssi_pid,
+                       child_pgid, info->ssi_signo, info->ssi_status);
+
+               while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+                       if (child_pid == child_pgid)
+                               killpg(child_pgid, SIGKILL);
+                       __sigchild_action(child_pid);
+               }
+       } else {
+               _D("queued signal: dead_pid = %d signo = %d", info->ssi_int,
+                       info->ssi_signo);
+               __sigchild_action(info->ssi_int);
        }
 }
 
index 55ea192b963dd7e59884aba920d811255770273d..39e9f210ef3751d42ea63447acbff89fb3261773 100644 (file)
@@ -41,6 +41,7 @@
 #define TAG_CPU_THRESHOLD_MAX          "CPU_THRESHOLD_MAX"
 #define TAG_CPU_THRESHOLD_MIN          "CPU_THRESHOLD_MIN"
 #define TAG_ON_BOOT                    "ON_BOOT"
+#define TAG_HYDRA                      "HYDRA"
 
 #define VAL_ON                         "ON"
 #define VAL_OFF                                "OFF"
@@ -79,6 +80,7 @@ static loader_info_t *__create_loader_info()
        info->activation_method = 0;
        info->deactivation_method = 0;
        info->ttl = 600; /* 10 minutes */
+       info->is_hydra = false;
 
        return info;
 }
@@ -294,6 +296,12 @@ static GList *__parse_file(GList *list, const char *path)
                } else if (strcasecmp(TAG_ON_BOOT, tok1) == 0) {
                        if (tok2 && strcasecmp(VAL_OFF, tok2) == 0)
                                cur_info->on_boot = false;
+               } else if (strcasecmp(TAG_HYDRA, tok1) == 0) {
+                       if (strcasecmp(VAL_ON, tok2) == 0) {
+                               cur_info->is_hydra = 1;
+                       } else {
+                               cur_info->is_hydra = 0;
+                       }
                }
        }