Fix hydra sigchld handler 17/235817/11
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 9 Jun 2020 11:53:46 +0000 (20:53 +0900)
committerHwanKyu Jhun <h.jhun@samsung.com>
Fri, 12 Jun 2020 01:31:31 +0000 (01:31 +0000)
When the child process of the hydra loader is dead, the hydra loader
sends the signal to the launchpad-process-pool.
This patch separates launchpad_signal.c file.

Change-Id: Idaddf9c963b331e1257fbeb8d8f1f985adbd9b0a
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
17 files changed:
src/common/inc/launchpad_common.h
src/common/inc/launchpad_proc.h
src/common/inc/launchpad_socket.h [new file with mode: 0644]
src/common/src/launchpad_common.c
src/common/src/launchpad_proc.c
src/common/src/launchpad_socket.c [new file with mode: 0644]
src/hydra/CMakeLists.txt
src/hydra/inc/launchpad_sigchld.h [new file with mode: 0644]
src/hydra/src/launchpad_hydra.c
src/hydra/src/launchpad_sigchld.c [new file with mode: 0644]
src/launchpad/inc/launchpad_dbus.h [new file with mode: 0644]
src/launchpad/inc/launchpad_io_channel.h
src/launchpad/inc/launchpad_signal.h
src/launchpad/src/launchpad.c
src/launchpad/src/launchpad_dbus.c [new file with mode: 0644]
src/launchpad/src/launchpad_io_channel.c
src/launchpad/src/launchpad_signal.c

index 5d97b77aae5d7579f91764963d18888883d7f1f1..0850aeddb5889a4ce050f7bf211e3e5bf108c730 100644 (file)
@@ -124,7 +124,6 @@ int _delete_sock_path(int pid, uid_t uid);
 appinfo_t *_appinfo_create(bundle *kb);
 void _appinfo_free(appinfo_t *menu_info);
 char *_appinfo_get_app_path(appinfo_t *menu_info);
-int _proc_get_attr_by_pid(int pid, char *buf, int size);
 int _close_all_fds(void);
 void _get_cpu_idle(unsigned long long *total, unsigned long long *idle);
 int _setup_stdio(const char *ident);
index eaff0f66a1f768a04e456d145a9e561c0c6bcd20..fe2b9ad7e3c345179c0c758642099dc0ffc4df2c 100644 (file)
 #ifndef __LAUNCHPAD_PROC_H__
 #define __LAUNCHPAD_PROC_H__
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int _proc_get_mem_used_ratio(unsigned int *mem_used_ratio);
 
 int _proc_get_mem_pss(int pid, unsigned int *mem_pss);
 
+int _proc_get_attr(int pid, void *buf, unsigned int size);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __LAUNCHPAD_PROC_H__ */
diff --git a/src/common/inc/launchpad_socket.h b/src/common/inc/launchpad_socket.h
new file mode 100644 (file)
index 0000000..b90de31
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LAUNCHPAD_SOCKET_H__
+#define __LAUNCHPAD_SOCKET_H__
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LAUNCHPAD_SOCKET_PATH_SIZE 108
+
+typedef struct socket_s *socket_h;
+
+int _socket_create(const char *path, bool client, socket_h *handle);
+
+int _socket_create_with_fd(int fd, socket_h *handle);
+
+int _socket_destroy(socket_h handle);
+
+int _socket_accept(socket_h handle, socket_h *client_socket);
+
+int _socket_get_fd(socket_h handle, int *fd);
+
+int _socket_set_fd(socket_h handle, int fd);
+
+int _socket_get_pid(socket_h handle, int *pid);
+
+int _socket_send(socket_h handle, const void *buf, unsigned int size);
+
+int _socket_read(socket_h handle, void *buf, unsigned int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LAUNCHPAD_SOCKET_H__ */
index 815bb303d15799fab608ad0e1fc6864c674442b8..e41a39101513937230cb93f92c133dcc7eae128e 100644 (file)
 #define PR_TASK_PERF_USER_TRACE 666
 #endif
 
-static int __read_proc(const char *path, char *buf, int size)
-{
-       int fd;
-       int ret;
-
-       if (buf == NULL || path == NULL)
-               return -1;
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
-               return -1;
-
-       ret = read(fd, buf, size - 1);
-       if (ret <= 0) {
-               close(fd);
-               return -1;
-       }
-
-       buf[ret] = 0;
-       close(fd);
-
-       return ret;
-}
-
 void _get_cpu_idle(unsigned long long *total, unsigned long long *idle)
 {
        FILE *fp;
@@ -847,19 +823,6 @@ char *_get_libdir(const char *path)
        return strdup(buf);
 }
 
-int _proc_get_attr_by_pid(int pid, char *buf, int size)
-{
-       char path[PATH_MAX] = { 0, };
-       int ret;
-
-       snprintf(path, sizeof(path), "/proc/%d/attr/current", pid);
-       ret = __read_proc(path, buf, size);
-       if (ret <= 0)
-               return -1;
-
-       return 0;
-}
-
 static int __delete_dir(const char *path)
 {
        DIR *dp;
index e491cff69f77e058744ed71d5801f64cf2bb9279..e390b2b78b027638496dbd3d645e3788e2c95210 100644 (file)
 
 #define _GNU_SOURCE
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <linux/limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "launchpad_proc.h"
 #include "log_private.h"
@@ -143,3 +147,46 @@ int _proc_get_mem_pss(int pid, unsigned int *mem_pss)
 
        return 0;
 }
+
+static void __close_fd(int *fd)
+{
+       if (!fd)
+               return;
+
+       if (*fd < 0)
+               return;
+
+       close(*fd);
+}
+
+int _proc_get_attr(int pid, void *buf, unsigned int size)
+{
+       auto_ptr(__close_fd) int fd = -1;
+       char path[PATH_MAX];
+       char *buffer = buf;
+       int ret;
+
+       if (pid < 1 || !buf || !size) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       snprintf(path, sizeof(path), "/proc/%d/attr/current", pid);
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               ret = -errno;
+               _E("open() is failed. errno(%d)", errno);
+               return ret;
+       }
+
+       ret = read(fd, buffer, size - 1);
+       if (ret < 0) {
+               ret = -errno;
+               _E("read() is failed. fd(%d), errno(%d)", fd, errno);
+               return ret;
+       }
+
+       buffer[ret] = 0;
+
+       return 0;
+}
diff --git a/src/common/src/launchpad_socket.c b/src/common/src/launchpad_socket.c
new file mode 100644 (file)
index 0000000..a79905b
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "launchpad_socket.h"
+#include "log_private.h"
+
+#define LAUNCHPAD_SOCKET_MAX_BUFF 131071
+#define LAUNCHPAD_SOCKET_RETRY_TIME (100 * 1000)
+#define LAUNCHPAD_SOCKET_RETRY_COUNT 3
+#define LAUNCHPAD_SOCKET_MAX_PENDING_CONNECTION 128
+
+struct socket_s {
+       char *path;
+       bool client;
+       int fd;
+       int pid;
+};
+
+static int __set_socket_option(int fd, bool client)
+{
+        struct timeval tv = { 5, 200 * 1000 };  /*  5.2 sec */
+        int size = LAUNCHPAD_SOCKET_MAX_BUFF;
+        int flag;
+        int ret;
+
+        ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
+        if (ret < 0) {
+               ret = -errno;
+               _E("setsockopt(SO_SNDBUF) is failed. fd(%d), errno(%d)",
+                               fd, errno);
+                return ret;
+        }
+
+        ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
+        if (ret < 0) {
+               ret = -errno;
+               _E("setsockopt(SO_RCVBUF) is failed. fd(%d), errno(%d)",
+                               fd, errno);
+                return ret;
+        }
+
+       if (!client)
+               return 0;
+
+       ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+       if (ret < 0) {
+               ret = -errno;
+               _E("setsockopt(SO_RCVTIMEO) is failed. fd(%d), errno(%d)",
+                               fd, errno);
+               return ret;
+       }
+
+       flag = fcntl(fd, F_GETFD);
+       flag |= FD_CLOEXEC;
+       ret = fcntl(fd, F_SETFD, flag);
+       if (ret < 0) {
+               ret = -errno;
+               _E("fcntl(F_SETFD) is failed. fd(%d), errno(%d)", fd, errno);
+               return ret;
+       }
+
+        return 0;
+}
+
+static int __create_server_socket(const char *path)
+{
+       struct sockaddr_un addr = { 0, };
+       int ret;
+       int fd;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               ret = -errno;
+               _E("socket() is failed. path(%s), errno(%d)", path, errno);
+               return ret;
+       }
+
+       addr.sun_family = AF_UNIX;
+       snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
+       unlink(addr.sun_path);
+
+       ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
+       if (ret < 0) {
+               ret = -errno;
+               _E("bind() is failed. path(%s), errno(%d)", path, errno);
+               close(fd);
+               return ret;
+       }
+
+       ret = __set_socket_option(fd, false);
+       if (ret < 0) {
+               close(fd);
+               return ret;
+       }
+
+       ret = listen(fd, LAUNCHPAD_SOCKET_MAX_PENDING_CONNECTION);
+       if (ret < 0) {
+               ret = -errno;
+               _E("listen() is failed. path(%s), errno(%d)", path, errno);
+               close(fd);
+               return ret;
+       }
+
+       return fd;
+}
+
+static int __create_client_socket(const char *path)
+{
+       struct sockaddr_un addr = { 0, };
+       int retry = LAUNCHPAD_SOCKET_RETRY_COUNT;
+       int ret;
+       int fd;
+
+       fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+        if (fd < 0) {
+               ret = -errno;
+               _E("socket() is failed. path(%s), errno(%d)", path, errno);
+                return ret;
+        }
+
+        addr.sun_family = AF_UNIX;
+        snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
+        while (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+                if (errno != ETIMEDOUT || retry <= 0) {
+                       ret = -errno;
+                       _E("connect() is failed. path(%s), errno(%d)",
+                                       path, errno);
+                        close(fd);
+                        return ret;
+                }
+
+                usleep(LAUNCHPAD_SOCKET_RETRY_TIME);
+                retry--;
+                _W("Retry(%d) to connect to %s", retry, path);
+        }
+
+       ret = __set_socket_option(fd, true);
+       if (ret < 0) {
+               close(fd);
+               return ret;
+       }
+
+       return fd;
+}
+
+static void __destroy_socket(struct socket_s *sock)
+{
+       if (!sock)
+               return;
+
+       if (!sock->client && sock->fd > 0 && sock->path)
+               unlink(sock->path);
+
+       free(sock->path);
+       free(sock);
+}
+
+static struct socket_s *__create_socket(const char *path, bool client,
+               int fd, int pid)
+{
+       struct socket_s *sock;
+
+       sock = calloc(1, sizeof(struct socket_s));
+       if (!sock) {
+               _E("Out of memory");
+               return NULL;
+       }
+
+       if (path) {
+               sock->path = strdup(path);
+               if (!sock->path) {
+                       _E("Failed to duplicate socket path(%s)", path);
+                       __destroy_socket(sock);
+                       return NULL;
+               }
+       }
+
+       sock->client = client;
+       sock->fd = fd;
+       sock->pid = pid;
+
+       return sock;
+}
+
+int _socket_create(const char *path, bool client, socket_h *handle)
+{
+       struct socket_s *sock;
+       int fd;
+
+       if (!path || !handle) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       if (client)
+               fd = __create_client_socket(path);
+       else
+               fd = __create_server_socket(path);
+
+       if (fd < 0)
+               return fd;
+
+       sock = __create_socket(path, client, fd, getpid());
+       if (!sock) {
+               close(fd);
+               return -ENOMEM;
+       }
+
+       *handle = sock;
+
+       return 0;
+}
+
+int _socket_create_with_fd(int fd, socket_h *handle)
+{
+       struct socket_s *sock;
+
+       if (fd < 0 || !handle) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       sock = __create_socket(NULL, true, fd, getpid());
+       if (!sock)
+               return -ENOMEM;
+
+       *handle = sock;
+
+       return 0;
+}
+
+int _socket_destroy(socket_h handle)
+{
+       if (!handle) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       if (handle->fd > 0)
+               close(handle->fd);
+
+       __destroy_socket(handle);
+
+       return 0;
+}
+
+int _socket_accept(socket_h handle, socket_h *client_socket)
+{
+       struct socket_s *sock;
+       struct sockaddr_un addr = { 0, };
+       struct ucred cred = { 0, };
+       socklen_t addr_size = sizeof(struct sockaddr_un);
+       socklen_t cred_size = sizeof(struct ucred);
+       int client_fd;
+       int ret;
+
+       if (!handle || !client_socket) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       client_fd = accept(handle->fd, (struct sockaddr *)&addr, &addr_size);
+       if (client_fd < 0) {
+               ret = -errno;
+               _E("accept() is failed. errno(%d)", errno);
+               return ret;
+       }
+
+       ret = getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &cred, &cred_size);
+       if (ret < 0) {
+               ret = -errno;
+               _E("getsockopt(SO_PEERCRED) is failed. errno(%d)", errno);
+               close(client_fd);
+               return ret;
+       }
+
+       ret = __set_socket_option(client_fd, true);
+       if (ret < 0) {
+               close(client_fd);
+               return ret;
+       }
+
+       sock = __create_socket(NULL, true, client_fd, cred.pid);
+       if (!sock) {
+               close(client_fd);
+               return -ENOMEM;
+       }
+
+       *client_socket = sock;
+
+       return 0;
+}
+
+int _socket_get_fd(socket_h handle, int *fd)
+{
+       if (!handle || !fd) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       *fd = handle->fd;
+
+       return 0;
+}
+
+int _socket_set_fd(socket_h handle, int fd)
+{
+       if (!handle) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       handle->fd = fd;
+
+       return 0;
+}
+
+int _socket_get_pid(socket_h handle, int *pid)
+{
+       if (!handle || !pid) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       *pid = handle->pid;
+
+       return 0;
+}
+
+int _socket_send(socket_h handle, const void *buf, unsigned int size)
+{
+       unsigned char *buffer = (unsigned char *)buf;
+       unsigned int left = size;
+       ssize_t write_size;
+       int ret;
+
+       if (!handle || !buf || !size) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       while (left) {
+               write_size = send(handle->fd, buffer, left, MSG_NOSIGNAL);
+               if (write_size < 0) {
+                       ret = -errno;
+                       _E("send() is failed. fd(%d), errno(%d)",
+                                       handle->fd, errno);
+                       return ret;
+               }
+
+               left -= write_size;
+               buffer += write_size;
+       }
+
+       return 0;
+}
+
+int _socket_read(socket_h handle, void *buf, unsigned int size)
+{
+       unsigned char *buffer = (unsigned char *)buf;
+       unsigned int left = size;
+       ssize_t read_size;
+
+       if (!handle || !buf || !size) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       while (left) {
+               read_size = read(handle->fd, buffer, left);
+               if (read_size == 0) {
+                       _W("EOF. fd(%d)", handle->fd);
+                       return -EIO;
+               } else if (read_size < 0) {
+                       return -errno;
+               }
+
+               left -= read_size;
+               buffer += read_size;
+       }
+
+       return 0;
+}
index 0ff9ebee721a639ea80daa05e2b894c63abbe151..6aeab28bbf000e8083436f380724d58dba676f91 100644 (file)
@@ -27,8 +27,12 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/inc)
 INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/src/common/inc)
 
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src SOURCES)
+SET(COMMON_SOURCES
+       ${CMAKE_SOURCE_DIR}/src/common/src/launchpad_socket.c)
 
-ADD_LIBRARY(${LAUNCHPAD_HYDRA} SHARED ${SOURCES})
+ADD_LIBRARY(${LAUNCHPAD_HYDRA} SHARED
+       ${SOURCES}
+       ${COMMON_SOURCES})
 SET_TARGET_PROPERTIES(${LAUNCHPAD_HYDRA} PROPERTIES SOVERSION ${MAJORVER})
 SET_TARGET_PROPERTIES(${LAUNCHPAD_HYDRA} PROPERTIES VERSION ${VERSION})
 SET_TARGET_PROPERTIES(${LAUNCHPAD_HYDRA} PROPERTIES COMPILE_FLAGS ${EXTRA_CFLAGS_hydra})
diff --git a/src/hydra/inc/launchpad_sigchld.h b/src/hydra/inc/launchpad_sigchld.h
new file mode 100644 (file)
index 0000000..bd4b968
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LAUNCHPAD_SIGCHLD_H__
+#define __LAUNCHPAD_SIGCHLD_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _sigchld_send(int pid);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LAUNCHPAD_SIGCHLD_H__ */
index 3b945559442452bb9d55db5efe995feab6db6e14..aa737fd3aa5cb9a8fa2646f63211e403ffba3473 100644 (file)
@@ -32,6 +32,7 @@
 #include <systemd/sd-event.h>
 
 #include "launchpad_hydra.h"
+#include "launchpad_sigchld.h"
 #include "launchpad_types.h"
 #include "log_private.h"
 
@@ -211,13 +212,12 @@ err:
 
 static int __process_sigchld(struct signalfd_siginfo *info)
 {
-       union sigval val;
        int status;
        pid_t child_pid;
        pid_t child_pgid;
 
        child_pgid = getpgid(info->ssi_pid);
-       _D("[__HYDRA__] Dead pid(%d), pgid(%d), signo(%d), status(%d)",
+       _W("[__HYDRA__] Dead pid(%d), pgid(%d), signo(%d), status(%d)",
                        info->ssi_pid, child_pgid, info->ssi_signo,
                        info->ssi_status);
 
@@ -225,8 +225,7 @@ static int __process_sigchld(struct signalfd_siginfo *info)
                if (child_pid == child_pgid)
                        killpg(child_pgid, SIGKILL);
 
-               val.sival_int = child_pid;
-               sigqueue(getppid(), SIGCHLD, val);
+               _sigchld_send(child_pid);
        }
 
        return 0;
diff --git a/src/hydra/src/launchpad_sigchld.c b/src/hydra/src/launchpad_sigchld.c
new file mode 100644 (file)
index 0000000..487cf99
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "launchpad_sigchld.h"
+#include "launchpad_socket.h"
+#include "log_private.h"
+
+#define HYDRA_SIGCHLD_SOCK ".hydra-sigchld-sock"
+
+int _sigchld_send(int pid)
+{
+       socket_h sock;
+       char path[LAUNCHPAD_SOCKET_PATH_SIZE];
+       int ret;
+
+       if (pid <= 1) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       snprintf(path, sizeof(path), "/run/aul/daemons/%u/%s",
+                       getuid(), HYDRA_SIGCHLD_SOCK);
+       ret = _socket_create(path, true, &sock);
+       if (ret < 0)
+               return ret;
+
+       ret = _socket_send(sock, &pid, sizeof(pid));
+       _socket_destroy(sock);
+
+       return ret;
+}
diff --git a/src/launchpad/inc/launchpad_dbus.h b/src/launchpad/inc/launchpad_dbus.h
new file mode 100644 (file)
index 0000000..685d89a
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __LAUNCHPAD_DBUS_H__
+#define __LAUNCHPAD_DBUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _dbus_send_app_launch_signal(int pid, const char *app_id);
+
+int _dbus_send_app_dead_signal(int pid);
+
+int _dbus_init(void);
+
+void _dbus_fini(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LAUNCHPAD_DBUS_H__ */
index 6498fb379feb3280d9be47bd70796110d7678a81..b9ae867e3d6dd5695d0d0e10ae29ffc5a1ebd319 100644 (file)
@@ -36,3 +36,5 @@ io_channel_h _io_channel_create(int fd, io_condition_e condition,
                io_channel_event_cb, void *user_data);
 
 void _io_channel_destroy(io_channel_h channel);
+
+int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close);
index a2dbccb625030163b1e302bb30d446f40079c8be..aea56542835d159aa0ae73ec4bc2ddf3b3f8ed43 100644 (file)
@@ -1,14 +1,14 @@
 /*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
- * Licensed under the Apache License, Version 2.0 (the License);
+ * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS,
+ * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
 #ifndef __LAUNCHPAD_SIGNAL_H__
 #define __LAUNCHPAD_SIGNAL_H__
 
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/signalfd.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*signal_sigchld_cb)(int pid, void *user_data);
+
+int _signal_set_sigchld_cb(signal_sigchld_cb callback, void *user_data);
 
-int _signal_send_app_launch_signal(int launch_pid, const char *app_id);
-void _signal_process_sigchld(struct signalfd_siginfo *info);
-int _signal_get_sigchld_fd(void);
-int _signal_unblock_sigchld(void);
 int _signal_init(void);
+
 void _signal_fini(void);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __LAUNCHPAD_SIGNAL_H__ */
index 217be8063228645fb7365deb6fe0e28cfe86af5a..02aab1bb9a5fe93865669ec14a0908a94736aab5 100644 (file)
@@ -43,6 +43,7 @@
 #include "launcher_info.h"
 #include "launchpad_common.h"
 #include "launchpad_config.h"
+#include "launchpad_dbus.h"
 #include "launchpad_debug.h"
 #include "launchpad_inotify.h"
 #include "launchpad_io_channel.h"
@@ -173,7 +174,6 @@ static int MAX_CPU_CHECK_COUNT;
 
 static io_channel_h __logger_channel;
 static io_channel_h __label_monitor_channel;
-static io_channel_h __sigchild_channel;
 static io_channel_h __launchpad_channel;
 
 static candidate_process_context_t *__add_slot(int type, int loader_id,
@@ -781,7 +781,7 @@ static int __exec_loader_process(void *arg)
        char err_buf[1024];
 
        _send_cmd_to_amd(LAUNCHPAD_CHILD_PROCESS);
-       _signal_unblock_sigchld();
+       _signal_fini();
        _close_all_fds();
        _setup_stdio(basename(argv[LOADER_ARG_PATH]));
 
@@ -1296,7 +1296,7 @@ static int __exec_app_process(void *arg)
        if (bundle_get_type(launch_arg->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
                _debug_prepare_debugger(launch_arg->kb);
 
-       _signal_unblock_sigchld();
+       _signal_fini();
 
        _delete_sock_path(getpid(), getuid());
 
@@ -1354,9 +1354,6 @@ static int __launchpad_pre_init(int argc, char **argv)
 {
        int fd;
 
-       /* signal init*/
-       _signal_init();
-
        /* create launchpad sock */
        fd = __create_sock_activation();
        if (fd < 0) {
@@ -1483,56 +1480,36 @@ static bool __handle_hydra_event(int fd, io_condition_e cond, void *data)
        return true;
 }
 
-static bool __handle_sigchild(int fd, io_condition_e cond, void *data)
+static void __handle_sigchild(int pid, void *user_data)
 {
        candidate_process_context_t *cpc;
-       struct signalfd_siginfo siginfo;
-       ssize_t s;
        char *appid;
-       int pid;
-
-       do {
-               s = read(fd, &siginfo, sizeof(struct signalfd_siginfo));
-               if (s == 0)
-                       break;
-
-               if (s != sizeof(struct signalfd_siginfo))
-                       break;
 
-               _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(pid));
-               if (appid) {
-                       security_manager_cleanup_app(appid, siginfo.ssi_uid, pid);
-                       g_hash_table_remove(__pid_table,
-                                       GINT_TO_POINTER(pid));
-               }
+       appid = g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid));
+       if (appid) {
+               security_manager_cleanup_app(appid, getuid(), pid);
+               g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
+       }
 
-               cpc = __find_slot_from_pid(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->pid = CANDIDATE_NONE;
-                       __dispose_candidate_process(cpc);
+                       cpc->hydra_pid = HYDRA_NONE;
+                       __dispose_hydra_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(pid);
+       while (cpc) {
+               __remove_slot(LAUNCHPAD_LOADER_TYPE_DYNAMIC, cpc->loader_id);
                cpc = __find_slot_from_caller_pid(pid);
-               while (cpc) {
-                       __remove_slot(LAUNCHPAD_LOADER_TYPE_DYNAMIC, cpc->loader_id);
-                       cpc = __find_slot_from_caller_pid(pid);
-               }
-       } while (s > 0);
-
-       return true;
+       }
 }
 
 static bool __handle_label_monitor(int fd, io_condition_e cond, void *data)
@@ -1841,7 +1818,7 @@ static int __check_caller_by_pid(int pid)
        int ret;
        char buf[PATH_MAX] = { 0, };
 
-       ret = _proc_get_attr_by_pid(pid, buf, sizeof(buf));
+       ret = _proc_get_attr(pid, buf, sizeof(buf));
        if (ret < 0)
                return -1;
 
@@ -2214,7 +2191,7 @@ end:
                close(clifd);
 
        if (pid > 0) {
-               _signal_send_app_launch_signal(pid, menu_info->appid);
+               _dbus_send_app_launch_signal(pid, menu_info->appid);
                g_hash_table_insert(__pid_table, GINT_TO_POINTER(pid),
                                strdup(menu_info->appid));
        }
@@ -2449,26 +2426,6 @@ static int __init_launchpad_fd(int argc, char **argv)
        return 0;
 }
 
-static int __init_sigchild_fd(void)
-{
-       int fd = -1;
-
-       fd = _signal_get_sigchld_fd();
-       if (fd < 0) {
-               _E("failed to get sigchld fd");
-               return -1;
-       }
-
-       __sigchild_channel = _io_channel_create(fd, IO_IN,
-                       __handle_sigchild, NULL);
-       if (!__sigchild_channel) {
-               close(fd);
-               return -1;
-       }
-
-       return 0;
-}
-
 static bool __on_directory_create(const char *event_name, uint32_t mask,
                void *user_data)
 {
@@ -2967,12 +2924,14 @@ static int __before_loop(int argc, char **argv)
                return -1;
        }
 
-       ret = __init_sigchild_fd();
-       if (ret != 0) {
-               _E("__init_sigchild_fd() failed");
+       ret = _signal_init();
+       if (ret < 0) {
+               _E("Failed to initialize signal");
                return -1;
        }
 
+       _signal_set_sigchld_cb(__handle_sigchild, NULL);
+
        ret = __init_launchpad_fd(argc, argv);
        if (ret != 0) {
                _E("__init_launchpad_fd() failed");
@@ -2993,6 +2952,10 @@ static int __before_loop(int argc, char **argv)
        if (ret != 0)
                _W("Failed to initialize config");
 
+       ret = _dbus_init();
+       if (ret != 0)
+               _W("Failed to initialize dbus");
+
        _inotify_init();
 
        MAX_CPU_CHECK_COUNT = _config_get_int_value(
@@ -3033,6 +2996,7 @@ static void __after_loop(void)
 
        _debug_fini();
        _launcher_info_unload(launcher_info_list);
+       _dbus_fini();
        _config_fini();
        _inotify_fini();
        _loader_info_dispose(app_defined_loader_info_list);
@@ -3049,8 +3013,7 @@ static void __after_loop(void)
        if (__launchpad_channel)
                _io_channel_destroy(__launchpad_channel);
 
-       if (__sigchild_channel)
-               _io_channel_destroy(__sigchild_channel);
+       _signal_fini();
 
        __sequencer_fini();
 }
diff --git a/src/launchpad/src/launchpad_dbus.c b/src/launchpad/src/launchpad_dbus.c
new file mode 100644 (file)
index 0000000..f1446f1
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <gio/gio.h>
+#include <glib.h>
+
+#include "launchpad_dbus.h"
+#include "log_private.h"
+
+#define AUL_DBUS_PATH                   "/aul/dbus_handler"
+#define AUL_DBUS_SIGNAL_INTERFACE       "org.tizen.aul.signal"
+#define AUL_DBUS_APPDEAD_SIGNAL         "app_dead"
+#define AUL_DBUS_APPLAUNCH_SIGNAL       "app_launch"
+
+#define PENDING_ITEM_INTERVAL           1000
+
+typedef enum {
+       APP_SIGNAL_DEAD,
+       APP_SIGNAL_LAUNCH,
+} app_signal_e;
+
+typedef struct pending_item_s {
+       char *app_id;
+       int pid;
+       app_signal_e app_signal;
+} pending_item_t;
+
+static GList *__pending_items;
+static guint __timer;
+static GDBusConnection *__conn;
+
+static void __set_pending_item_timer(void);
+
+static void __destroy_pending_item(gpointer data)
+{
+       pending_item_t *item = data;
+
+       free(item->app_id);
+       free(item);
+}
+
+static pending_item_t *__create_pending_item(const char *app_id,
+               int pid, app_signal_e app_signal)
+{
+       pending_item_t *item;
+
+       item = calloc(1, sizeof(pending_item_t));
+       if (!item) {
+               _E("Out of memory");
+               return NULL;
+       }
+
+       if (app_id) {
+               item->app_id = strdup(app_id);
+               if (!item->app_id) {
+                       _E("Failed to duplicate app ID(%s)", app_id);
+                       __destroy_pending_item(item);
+                       return NULL;
+               }
+       }
+
+       item->pid = pid;
+       item->app_signal = app_signal;
+
+       return item;
+}
+
+static GDBusConnection *__get_connection(void)
+{
+       GError *error = NULL;
+
+       if (__conn)
+               return __conn;
+
+       __conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!__conn) {
+               _E("g_bus_get_sync() is failed. error(%s)",
+                               error ? error->message : "Unknown");
+               g_clear_error(&error);
+               return NULL;
+       }
+
+       return __conn;
+}
+
+static int __emit_signal(const char *path,
+               const char *interface,
+               const char *signal,
+               GVariant *param)
+{
+       GDBusConnection *conn;
+       GError *error = NULL;
+       gboolean ret;
+
+       conn = __get_connection();
+       if (!conn)
+               return -1;
+
+       ret = g_dbus_connection_emit_signal(conn,
+                       NULL,
+                       path,
+                       interface,
+                       signal,
+                       param,
+                       &error);
+       if (ret != TRUE) {
+               _E("g_dbus_connection_emit_signal() is failed. error(%s)",
+                               error ? error->message : "Unknown");
+               g_clear_error(&error);
+               return -1;
+       }
+
+       ret = g_dbus_connection_flush_sync(conn, NULL, &error);
+       if (ret != TRUE) {
+               _E("g_dbus_connection_flush_sync() is failed. error(%s)",
+                               error ? error->message : "Unknown");
+               g_clear_error(&error);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int __emit_app_launch_signal(int pid, const char *app_id)
+{
+       pending_item_t *item;
+       int ret;
+
+       ret = __emit_signal(AUL_DBUS_PATH,
+                       AUL_DBUS_SIGNAL_INTERFACE,
+                       AUL_DBUS_APPLAUNCH_SIGNAL,
+                       g_variant_new("(us)", pid, app_id));
+       if (ret < 0) {
+               item = __create_pending_item(app_id, pid, APP_SIGNAL_LAUNCH);
+               if (!item)
+                       return -ENOMEM;
+
+               _W("Pend app launch signal. pid(%d), app_id(%s)", pid, app_id);
+               __pending_items = g_list_append(__pending_items, item);
+               __set_pending_item_timer();
+       } else {
+               _D("App launch. pid(%d), app_id(%s)", pid, app_id);
+       }
+
+       return 0;
+}
+
+static int __emit_app_dead_signal(int pid)
+{
+       pending_item_t *item;
+       int ret;
+
+       ret = __emit_signal(AUL_DBUS_PATH,
+                       AUL_DBUS_SIGNAL_INTERFACE,
+                       AUL_DBUS_APPDEAD_SIGNAL,
+                       g_variant_new("(u)", pid));
+       if (ret < 0) {
+               item = __create_pending_item(NULL, pid, APP_SIGNAL_DEAD);
+               if (!item)
+                       return -ENOMEM;
+
+               _W("Pend app dead signal. pid(%d)", pid);
+               __pending_items = g_list_append(__pending_items, item);
+               __set_pending_item_timer();
+       } else {
+               _D("App dead. pid(%d)", pid);
+       }
+
+       return 0;
+}
+
+static gboolean __flush_pending_item(gpointer data)
+{
+       pending_item_t *item;
+       GList *iter;
+       int ret;
+
+       if (!__pending_items) {
+               __timer = 0;
+               return G_SOURCE_REMOVE;
+       }
+
+       iter = __pending_items;
+       while (iter) {
+               item = (pending_item_t *)iter->data;
+               if (item->app_signal == APP_SIGNAL_DEAD)
+                       ret = __emit_app_dead_signal(item->pid);
+               else
+                       ret = __emit_app_launch_signal(item->pid, item->app_id);
+
+               if (ret < 0)
+                       return G_SOURCE_CONTINUE;
+
+               iter = g_list_next(iter);
+               __pending_items = g_list_remove(__pending_items, item);
+               __destroy_pending_item(item);
+       }
+
+       __timer = 0;
+       return G_SOURCE_REMOVE;
+}
+
+static void __set_pending_item_timer(void)
+{
+       if (__timer)
+               return;
+
+       __timer = g_timeout_add(PENDING_ITEM_INTERVAL,
+                       __flush_pending_item, NULL);
+}
+
+static void __unset_pending_item_timer(void)
+{
+       if (!__timer)
+               return;
+
+       g_source_remove(__timer);
+       __timer = 0;
+}
+
+int _dbus_send_app_launch_signal(int pid, const char *app_id)
+{
+       if (pid <= 1 || !app_id) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       return __emit_app_launch_signal(pid, app_id);
+}
+
+int _dbus_send_app_dead_signal(int pid)
+{
+       if (pid <= 1) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       return __emit_app_dead_signal(pid);
+}
+
+int _dbus_init(void)
+{
+       GDBusConnection *conn;
+
+       _D("DBUS_INIT");
+       conn = __get_connection();
+       if (!conn)
+               return -1;
+
+       return 0;
+}
+
+void _dbus_fini(void)
+{
+       _D("DBUS_FINI");
+       if (__pending_items)
+               g_list_free_full(__pending_items, __destroy_pending_item);
+
+       __unset_pending_item_timer();
+
+       if (__conn)
+               g_object_unref(__conn);
+}
index f20cb9254967c5228d4addd34665c07fafd19308..31529a365558fa01347874b48c2f0e932b531e73 100644 (file)
@@ -28,6 +28,7 @@
 struct io_channel_s {
        GIOChannel *io;
        guint tag;
+       bool do_close;
        int fd;
        io_channel_event_cb callback;
        void *user_data;
@@ -96,8 +97,9 @@ static gboolean __io_event_cb(GIOChannel *source, GIOCondition condition,
 {
        io_channel_h channel = (io_channel_h)data;
        io_condition_e cond = __convert_g_io_condition(condition);
+       int fd = g_io_channel_unix_get_fd(source);
 
-       if (!channel->callback(channel->fd, cond, channel->user_data))
+       if (!channel->callback(fd, cond, channel->user_data))
                return G_SOURCE_REMOVE;
 
        return G_SOURCE_CONTINUE;
@@ -134,6 +136,7 @@ io_channel_h _io_channel_create(int fd, io_condition_e cond,
                return NULL;
        }
 
+       channel->do_close = true;
        channel->fd = fd;
        channel->callback = callback;
        channel->user_data = user_data;
@@ -152,8 +155,20 @@ void _io_channel_destroy(io_channel_h channel)
        if (channel->io)
                g_io_channel_unref(channel->io);
 
-       if (channel->fd)
+       if (channel->do_close && channel->fd > 0)
                close(channel->fd);
 
        free(channel);
 }
+
+int _io_channel_set_close_on_destroy(io_channel_h channel, bool do_close)
+{
+       if (!channel) {
+               _E("Invalid parameter");
+               return -EINVAL;
+       }
+
+       channel->do_close = do_close;
+
+       return 0;
+}
index 8dbf5658647b6735853d1c20a2eb5a5e07176840..5ee306732b51f048909448c1b04470c167f489ff 100644 (file)
 /*
- * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2015 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
  *
- * Licensed under the Apache License, Version 2.0 (the License);
+ * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS,
+ * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #define _GNU_SOURCE
+#include <dirent.h>
+#include <gio/gio.h>
+#include <glib.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <dirent.h>
+#include <sys/signalfd.h>
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <gio/gio.h>
-#include <glib.h>
+#include <unistd.h>
 
 #include "launchpad_common.h"
+#include "launchpad_dbus.h"
+#include "launchpad_io_channel.h"
+#include "launchpad_proc.h"
 #include "launchpad_signal.h"
+#include "launchpad_socket.h"
+#include "log_private.h"
+
+#define HYDRA_SIGCHLD_SOCK          ".hydra-sigchld-sock"
 
-#define AUL_DBUS_PATH                  "/aul/dbus_handler"
-#define AUL_DBUS_SIGNAL_INTERFACE      "org.tizen.aul.signal"
-#define AUL_DBUS_APPDEAD_SIGNAL                "app_dead"
-#define AUL_DBUS_APPLAUNCH_SIGNAL      "app_launch"
-#define PENDING_SIGNAL_INTERVAL                1000
-
-enum signal_e {
-       APP_DEAD,
-       APP_LAUNCH,
-};
-
-struct pending_signal {
-       char *appid;
-       int pid;
-       int signal;
-};
-
-static GDBusConnection *bus;
-static sigset_t oldmask;
-static GList *pending_signal_list;
-static guint timeout_handle;
-
-static int __send_app_dead_signal(int dead_pid);
-static int __send_app_launch_signal(int launch_pid, const char *app_id);
-
-static struct pending_signal *__create_pending_signal(const char *appid,
-               const int pid, const int signal)
+static pid_t __pid;
+static sigset_t __old_mask;
+static socket_h __sigchld_socket;
+static io_channel_h __sigchld_channel;
+static socket_h __hydra_sigchld_socket;
+static io_channel_h __hydra_sigchld_channel;
+static signal_sigchld_cb __callback;
+static void *__user_data;
+
+static void __socket_garbage_collector(void)
 {
-       struct pending_signal *handle;
+       DIR *dp;
+       struct dirent *dentry = NULL;
+       char path[PATH_MAX];
 
-       handle = (struct pending_signal *)calloc(1,
-                       sizeof(struct pending_signal));
-       if (handle == NULL) {
-               _E("out of memory");
-               return NULL;
-       }
+       snprintf(path, sizeof(path), "/run/aul/apps/%d", getuid());
+       dp = opendir(path);
+       if (!dp)
+               return;
 
-       if (appid) {
-               handle->appid = strdup(appid);
-               if (handle->appid == NULL) {
-                       _E("out of memory");
-                       free(handle);
-                       return NULL;
-               }
-       }
+       while ((dentry = readdir(dp)) != NULL) {
+               if (!isdigit(dentry->d_name[0]))
+                       continue;
 
-       handle->pid = pid;
-       handle->signal = signal;
+               snprintf(path, sizeof(path), "/proc/%s", dentry->d_name);
+               if (access(path, F_OK) < 0)
+                       _delete_sock_path(atoi(dentry->d_name), getuid());
+       }
+       closedir(dp);
+}
 
-       return handle;
+static void __sigchld_action(int pid)
+{
+       _dbus_send_app_dead_signal(pid);
+       _delete_sock_path(pid, getuid());
+       __socket_garbage_collector();
 }
 
-static void __destroy_pending_signal(struct pending_signal *handle)
+static int __check_permission(int pid)
 {
-       if (handle == NULL)
-               return;
+       char buf[512] = { 0, };
+       int ret;
 
-       if (handle->appid)
-               free(handle->appid);
-       free(handle);
+       ret = _proc_get_attr(pid, buf, sizeof(buf));
+       if (ret < 0)
+               return -1;
+
+       if (!strcmp(buf, "User") ||
+                       !strcmp(buf, "System") ||
+                       !strcmp(buf, "System::Privileged"))
+               return 0;
+
+       _E("Permission denied. peer(%d:%s)", pid, buf);
+       return -1;
 }
 
-static gboolean __flush_pending_signal(gpointer data)
+static bool __hydra_sigchld_handler(int fd, io_condition_e cond,
+               void *user_data)
 {
-       struct pending_signal *handle;
-       GList *iter;
+       socket_h client_socket;
+       int caller_pid;
+       int pid = -1;
        int ret;
 
-       if (pending_signal_list == NULL) {
-               timeout_handle = 0;
-               return FALSE;
+       ret = _socket_accept(__hydra_sigchld_socket, &client_socket);
+       if (ret < 0)
+               return true;
+
+       _socket_get_pid(client_socket, &caller_pid);
+       ret = __check_permission(caller_pid);
+       if (ret < 0) {
+               _socket_destroy(client_socket);
+               return true;
        }
 
-       iter = g_list_first(pending_signal_list);
-       while (iter) {
-               handle = (struct pending_signal *)iter->data;
-               iter = g_list_next(iter);
-               if (handle) {
-                       if (handle->signal == APP_DEAD) {
-                               ret = __send_app_dead_signal(handle->pid);
-                       } else {
-                               ret = __send_app_launch_signal(handle->pid,
-                                               handle->appid);
-                       }
-                       if (ret < 0)
-                               return TRUE;
-
-                       pending_signal_list = g_list_remove(pending_signal_list,
-                                       handle);
-                       __destroy_pending_signal(handle);
-               }
+       ret = _socket_read(client_socket, &pid, sizeof(pid));
+       _socket_destroy(client_socket);
+       if (ret < 0) {
+               _E("Failed to read process id. ret(%d)", ret);
+               return true;
        }
 
-       timeout_handle = 0;
+       _W("[__SIGCHLD__] pid(%d)", pid);
+       __sigchld_action(pid);
 
-       return FALSE;
+       if (__callback)
+               __callback(pid, user_data);
+
+       return true;
 }
 
-static void __socket_garbage_collector(void)
+static int __hydra_sigchld_init(void)
 {
-       DIR *dp;
-       struct dirent *dentry = NULL;
-       char tmp[PATH_MAX];
+       char path[LAUNCHPAD_SOCKET_PATH_SIZE];
+       io_channel_h channel;
+       socket_h socket;
+       int ret;
+       int fd;
 
-       snprintf(tmp, sizeof(tmp), "/run/aul/apps/%d", getuid());
-       dp = opendir(tmp);
-       if (dp == NULL)
-               return;
+       snprintf(path, sizeof(path), "/run/aul/daemons/%u/%s",
+                       getuid(), HYDRA_SIGCHLD_SOCK);
+       ret = _socket_create(path, false, &socket);
+       if (ret < 0)
+               return ret;
 
-       while ((dentry = readdir(dp)) != NULL) {
-               if (!isdigit(dentry->d_name[0]))
-                       continue;
+       _socket_get_fd(socket, &fd);
 
-               snprintf(tmp, sizeof(tmp), "/proc/%s", dentry->d_name);
-               if (access(tmp, F_OK) < 0) {    /* Flawfinder: ignore */
-                       _delete_sock_path(atoi(dentry->d_name), getuid());
-                       continue;
-               }
+       channel = _io_channel_create(fd, IO_IN | IO_PRI,
+                       __hydra_sigchld_handler, NULL);
+       if (!channel) {
+               _socket_destroy(socket);
+               return -ENOMEM;
        }
-       closedir(dp);
+
+       _io_channel_set_close_on_destroy(channel, false);
+
+       __hydra_sigchld_socket = socket;
+       __hydra_sigchld_channel = channel;
+
+       return 0;
 }
 
-static int __send_app_dead_signal(int dead_pid)
+static int __hydra_sigchld_fini(void)
 {
-       GError *err = NULL;
-
-       /* send over session dbus for other applications */
-       if (bus == NULL) {
-               bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
-               if (bus == NULL) {
-                       _E("Failed to connect to the D-BUS daemon: %s",
-                                       err->message);
-                       g_error_free(err);
-                       return -1;
-               }
-       }
+       if (__hydra_sigchld_channel)
+               _io_channel_destroy(__hydra_sigchld_channel);
 
-       if (g_dbus_connection_emit_signal(bus,
-                                       NULL,
-                                       AUL_DBUS_PATH,
-                                       AUL_DBUS_SIGNAL_INTERFACE,
-                                       AUL_DBUS_APPDEAD_SIGNAL,
-                                       g_variant_new("(u)", dead_pid),
-                                       &err) == FALSE) {
-               _E("g_dbus_connection_emit_signal() is failed: %s",
-                                       err->message);
-               g_error_free(err);
-               return -1;
-       }
+       if (__hydra_sigchld_socket) {
+               if (__pid != getpid())
+                       _socket_set_fd(__hydra_sigchld_socket, -1);
 
-       if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
-               _E("g_dbus_connection_flush_sync() is failed: %s",
-                                       err->message);
-               g_error_free(err);
-               return -1;
+               _socket_destroy(__hydra_sigchld_socket);
        }
 
-       _D("send_app_dead_signal_dbus done (pid=%d)", dead_pid);
-
        return 0;
 }
 
-static int __send_app_launch_signal(int launch_pid, const char *app_id)
+static bool __sigchld_handler(int fd, io_condition_e cond, void *user_data)
 {
-       GError *err = NULL;
-       GVariant *param;
-
-       if (bus == NULL) {
-               bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
-               if (bus == NULL) {
-                       _E("Failed to connect to the D-BUS daemon: %s",
-                                       err->message);
-                       g_error_free(err);
-                       return -1;
-               }
-       }
+       struct signalfd_siginfo info;
+       pid_t child_pid;
+       pid_t child_pgid;
+       int status;
+       int ret;
 
-       param = g_variant_new("(us)", launch_pid, app_id);
-       if (g_dbus_connection_emit_signal(bus,
-                                       NULL,
-                                       AUL_DBUS_PATH,
-                                       AUL_DBUS_SIGNAL_INTERFACE,
-                                       AUL_DBUS_APPLAUNCH_SIGNAL,
-                                       param,
-                                       &err) == FALSE) {
-               _E("g_dbus_connection_emit_signal() is failed: %s",
-                                       err->message);
-               g_error_free(err);
-               return -1;
-       }
+       do {
+               ret = _socket_read(__sigchld_socket, &info, sizeof(info));
+               if (ret < 0)
+                       break;
 
-       if (g_dbus_connection_flush_sync(bus, NULL, &err) == FALSE) {
-               _E("g_dbus_connection_flush_sync() is failed: %s",
-                                       err->message);
-               g_error_free(err);
-               return -1;
-       }
+               child_pgid = getpgid(info.ssi_pid);
+               _W("[__SIGCHLD__] pid(%d), pgid(%d), status(%d)",
+                               info.ssi_pid, child_pgid, info.ssi_status);
 
-       _D("send_app_launch_signal_dbus done (pid=%d)", launch_pid);
+               while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+                       if (child_pid == child_pgid)
+                               killpg(child_pgid, SIGKILL);
 
-       return 0;
+                       __sigchld_action(child_pid);
+               }
+
+               if (__callback)
+                       __callback(info.ssi_pid, __user_data);
+       } while (ret == 0);
+
+       return true;
 }
 
-int _signal_send_app_launch_signal(int launch_pid, const char *app_id)
+static int __sigchld_init(void)
 {
+       io_channel_h channel;
+       socket_h socket;
+       sigset_t mask;
+       int sfd;
        int ret;
-       struct pending_signal *handle;
 
-       ret = __send_app_launch_signal(launch_pid, app_id);
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGCHLD);
+
+       ret = sigprocmask(SIG_BLOCK, &mask, &__old_mask);
        if (ret < 0) {
-               handle = __create_pending_signal(app_id, launch_pid,
-                               APP_LAUNCH);
-               pending_signal_list = g_list_append(pending_signal_list,
-                               handle);
-               if (timeout_handle == 0) {
-                       timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
-                                       __flush_pending_signal, NULL);
-               }
-               return -1;
+               ret = -errno;
+               _E("sigprocmask(SIG_BLOCK) is failed. errno(%d)", errno);
+               return ret;
+       }
+
+       sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
+       if (sfd < 0) {
+               ret = -errno;
+               _E("signalfd() is failed. errno(%d)", errno);
+               return ret;
        }
 
+       ret = _socket_create_with_fd(sfd, &socket);
+       if (ret < 0) {
+               close(sfd);
+               return ret;
+       }
+
+       channel = _io_channel_create(sfd, IO_IN | IO_PRI,
+                       __sigchld_handler, NULL);
+       if (!channel) {
+               _socket_destroy(socket);
+               return -ENOMEM;
+       }
+       _io_channel_set_close_on_destroy(channel, false);
+
+       __sigchld_socket = socket;
+       __sigchld_channel = channel;
+
        return 0;
 }
 
-static int __sigchild_action(pid_t dead_pid)
+static int __sigchld_fini(void)
 {
        int ret;
-       struct pending_signal *handle;
 
-       if (dead_pid <= 0)
-               return 0;
+       if (__sigchld_channel)
+               _io_channel_destroy(__sigchld_channel);
 
-       ret = __send_app_dead_signal(dead_pid);
-       if (ret < 0) {
-               handle = __create_pending_signal(NULL, dead_pid, APP_DEAD);
-               pending_signal_list = g_list_append(pending_signal_list,
-                               handle);
-               if (timeout_handle == 0) {
-                       timeout_handle = g_timeout_add(PENDING_SIGNAL_INTERVAL,
-                                       __flush_pending_signal, NULL);
-               }
+       if (__sigchld_socket) {
+               if (__pid != getpid())
+                       _socket_set_fd(__sigchld_socket, -1);
+
+               _socket_destroy(__sigchld_socket);
        }
 
-       _delete_sock_path(dead_pid, getuid());
-       __socket_garbage_collector();
+       ret = sigprocmask(SIG_SETMASK, &__old_mask, NULL);
+       if (ret < 0) {
+               ret = -errno;
+               _E("sigprocmask(SIG_SETMASK) is failed. errno(%d)", errno);
+               return ret;
+       }
 
        return 0;
 }
 
-void _signal_process_sigchld(struct signalfd_siginfo *info)
+int _signal_set_sigchld_cb(signal_sigchld_cb callback, void *user_data)
 {
-       int status;
-       pid_t child_pid;
-       pid_t child_pgid;
-
-       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);
+       __callback = callback;
+       __user_data = user_data;
 
-               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);
-       }
+       return 0;
 }
 
 int _signal_init(void)
 {
+       int ret;
        int i;
-       GError *error = NULL;
 
-       bus = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
-       if (!bus) {
-               _E("Failed to connect to the D-BUS daemon: %s", error->message);
-               g_error_free(error);
-       }
+       _D("SIGNAL_INIT");
+       __pid = getpid();
+
+       ret = __sigchld_init();
+       if (ret < 0)
+               return ret;
 
-       for (i = 0; i < _NSIG; i++) {
+       ret = __hydra_sigchld_init();
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < _NSIG; ++i) {
                switch (i) {
-                       /* controlled by sys-assert package*/
+               /* controlled by sys-assert package*/
                case SIGQUIT:
                case SIGILL:
                case SIGABRT:
@@ -329,47 +316,17 @@ int _signal_init(void)
        return 0;
 }
 
-int _signal_get_sigchld_fd(void)
-{
-       sigset_t mask;
-       int sfd;
-
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGCHLD);
-
-       if (sigprocmask(SIG_BLOCK, &mask, &oldmask) == -1)
-               _E("failed to sigprocmask");
-
-       sfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
-       if (sfd == -1) {
-               _E("failed to create signal for SIGCHLD");
-               return -1;
-       }
-
-       return sfd;
-}
-
-int _signal_unblock_sigchld(void)
-{
-       if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
-               _E("SIG_SETMASK error");
-               return -1;
-       }
-
-       _D("SIGCHLD unblocked");
-       return 0;
-}
-
 void _signal_fini(void)
 {
 #ifndef PRELOAD_ACTIVATE
        int i;
 
-       for (i = 0; i < _NSIG; i++)
+       for (i = 0; i < _NSIG; ++i)
                signal(i, SIG_DFL);
 #endif
-       if (bus) {
-               g_object_unref(bus);
-               bus = NULL;
-       }
+
+       _D("SIGNAL_FINI");
+       _signal_set_sigchld_cb(NULL, NULL);
+       __hydra_sigchld_fini();
+       __sigchld_fini();
 }