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);
#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__ */
--- /dev/null
+/*
+ * 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__ */
#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;
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;
#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"
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;
+}
--- /dev/null
+/*
+ * 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;
+}
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})
--- /dev/null
+/*
+ * 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__ */
#include <systemd/sd-event.h>
#include "launchpad_hydra.h"
+#include "launchpad_sigchld.h"
#include "launchpad_types.h"
#include "log_private.h"
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);
if (child_pid == child_pgid)
killpg(child_pgid, SIGKILL);
- val.sival_int = child_pid;
- sigqueue(getppid(), SIGCHLD, val);
+ _sigchld_send(child_pid);
}
return 0;
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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__ */
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);
/*
- * 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__ */
#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"
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,
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]));
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());
{
int fd;
- /* signal init*/
- _signal_init();
-
/* create launchpad sock */
fd = __create_sock_activation();
if (fd < 0) {
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)
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;
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));
}
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)
{
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");
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(
_debug_fini();
_launcher_info_unload(launcher_info_list);
+ _dbus_fini();
_config_fini();
_inotify_fini();
_loader_info_dispose(app_defined_loader_info_list);
if (__launchpad_channel)
_io_channel_destroy(__launchpad_channel);
- if (__sigchild_channel)
- _io_channel_destroy(__sigchild_channel);
+ _signal_fini();
__sequencer_fini();
}
--- /dev/null
+/*
+ * 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);
+}
struct io_channel_s {
GIOChannel *io;
guint tag;
+ bool do_close;
int fd;
io_channel_event_cb callback;
void *user_data;
{
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;
return NULL;
}
+ channel->do_close = true;
channel->fd = fd;
channel->callback = callback;
channel->user_data = user_data;
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;
+}
/*
- * 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:
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();
}