The launchpad signal is implemented using C++ language.
Change-Id: I633d2a5d58f01b4fdf70df9613fb1dbd1a2c88b2
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "launchpad-process-pool/hydra_sigchld_event.hh"
+
+#include <string>
+
+#include <peer_credentials.hh>
+#include <procfs.hh>
+
+#include "launchpad-process-pool/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+constexpr const char HYDRA_SIGCHLD_SOCK[] = ".hydra-sigchld-sock";
+const int MAX_PENDING_CONNECTION = 128;
+const int MAX_RECEIVE_BUFFER = 131071;
+
+int CheckPermission(pid_t pid) {
+ std::string attr = Procfs::GetAttrCurrent(pid);
+ if (attr.empty())
+ return -1;
+
+ if (attr.compare("User") == 0 ||
+ attr.compare("System") == 0 ||
+ attr.compare("System::Privileged") == 0)
+ return 0;
+
+ _E("Permission denied. peer(%d:%s)", pid, attr.c_str());
+ return -1;
+}
+
+} // namespace
+
+HydraSigchldEvent::HydraSigchldEvent(IEvent* listener)
+ : listener_(listener),
+ socket_(new ServerSocket()) {
+ std::string endpoint = "/run/aul/daemons/" + std::to_string(getuid()) +
+ HYDRA_SIGCHLD_SOCK;
+ socket_->Bind(endpoint);
+ socket_->Listen(MAX_PENDING_CONNECTION);
+ socket_->SetReceiveBufferSize(MAX_RECEIVE_BUFFER);
+
+ channel_.reset(new IOChannel(socket_->GetFd(), IOChannel::IOCondition::IO_IN,
+ this));
+ channel_->SetCloseOnDestroy(false);
+}
+
+HydraSigchldEvent::~HydraSigchldEvent() {
+ if (getpid() != current_pid_)
+ socket_->RemoveFd();
+}
+
+void HydraSigchldEvent::OnIOEventReceived(int fd, int condition) {
+ auto client_socket = socket_->Accept();
+ if (!client_socket)
+ return;
+
+ auto peer_creds = PeerCredentials::Get(client_socket->GetFd());
+ if (!peer_creds) {
+ if (CheckPermission(peer_creds->GetPid()) != 0)
+ return;
+ }
+
+ pid_t pid = -1;
+ if (client_socket->Receive(&pid, sizeof(pid)) != 0)
+ return;
+
+ if (listener_ != nullptr)
+ listener_->OnHydraSigchld(pid);
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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_PROCESS_POOL_HYDRA_SIGCHLD_EVENT_HH_
+#define LAUNCHPAD_PROCESS_POOL_HYDRA_SIGCHLD_EVENT_HH_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <server_socket.hh>
+#include <io_channel.hh>
+
+namespace launchpad {
+
+class HydraSigchldEvent : public IOChannel::IEvent {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnHydraSigchld(pid_t pid) = 0;
+ };
+
+ explicit HydraSigchldEvent(IEvent* listener);
+ virtual ~HydraSigchldEvent();
+
+ private:
+ void OnIOEventReceived(int fd, int condition) override;
+
+ private:
+ IEvent* listener_;
+ std::unique_ptr<ServerSocket> socket_;
+ std::unique_ptr<IOChannel> channel_;
+ pid_t current_pid_ = getpid();
+};
+
+} // namespace launchpad
+
+#endif // LAUNCHPAD_PROCESS_POOL_HYDRA_SIGCHLD_EVENT_HH_
#include "launchpad-process-pool/launchpad_debug.h"
#include "launchpad-process-pool/launchpad_inotify.h"
#include "launchpad-process-pool/launchpad_io_channel.h"
-#include "launchpad-process-pool/launchpad_signal.h"
#include "launchpad-process-pool/loader_info.hh"
#include "launchpad-process-pool/slot_info.h"
#include "lib/common/inc/key.h"
#include "launchpad-process-pool/dbus.hh"
#include "launchpad-process-pool/log.hh"
#include "launchpad-process-pool/memory_monitor.hh"
+#include "launchpad-process-pool/signal_manager.hh"
#include "launchpad-process-pool/worker.hh"
#define AUL_PR_NAME 16
typedef int (*request_handler)(request_h request);
static void HandleMemoryStatusChangedEvent(bool low_memory);
+static void HandleSigchld(pid_t pid);
namespace {
}
};
+class SigchldHandler : public launchpad::SignalManager::IEvent {
+ private:
+ void OnSigchldReceived(pid_t pid) override {
+ HandleSigchld(pid);
+ }
+};
+
int __sys_hwacc;
std::unique_ptr<launchpad::LoaderInfoManager> loader_info_manager;
std::unique_ptr<launchpad::LoaderInfoManager> app_defined_loader_info_manager;
int __client_fd = -1;
launchpad::AsanAppChecker __asan_app_checker;
std::unique_ptr<launchpad::Worker> cleaner;
+SigchldHandler sigchld_handler;
} // namespace
char** argv = static_cast<char**>(arg);
char err_buf[1024];
- _signal_unblock_sigchld();
+ launchpad::SignalManager::GetInst().UnblockSigchld();
_close_all_fds();
_setup_stdio(basename(argv[LOADER_ARG_PATH]));
setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
}
- _signal_unblock_sigchld();
-
+ launchpad::SignalManager::GetInst().UnblockSigchld();
_delete_sock_path(getpid(), getuid());
PERF("prepare exec - first done");
return true;
}
-static void __handle_sigchild(int pid, void* user_data) {
+static void HandleSigchld(pid_t pid) {
char* appid = static_cast<char*>(
g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid)));
if (appid) {
return -1;
}
- ret = _signal_init();
- if (ret < 0) {
- _E("Failed to initialize signal");
- return -1;
- }
-
- _signal_set_sigchld_cb(__handle_sigchild, nullptr);
+ launchpad::SignalManager::GetInst().SetEventListener(&sigchld_handler);
ret = __init_launchpad_fd(argc, argv);
if (ret != 0) {
if (__launchpad_channel)
_io_channel_destroy(__launchpad_channel);
- _signal_fini();
+ launchpad::SignalManager::GetInst().Dispose();
__sequencer_fini();
}
+++ /dev/null
-/*
- * Copyright (c) 2015 - 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.
- */
-
-#include "launchpad-process-pool/launchpad_signal.h"
-
-#include <dirent.h>
-#include <gio/gio.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/signalfd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <filesystem>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "launchpad-process-pool/launchpad_io_channel.h"
-#include "lib/common/inc/launchpad_common.h"
-#include "lib/common/inc/launchpad_proc.h"
-#include "lib/common/inc/launchpad_socket.h"
-#include "lib/common/inc/log_private.h"
-
-#include "launchpad-process-pool/dbus.hh"
-#include "launchpad-process-pool/log_private.hh"
-#include "launchpad-process-pool/worker.hh"
-
-namespace fs = std::filesystem;
-
-namespace {
-
-constexpr const char HYDRA_SIGCHLD_SOCK[] = ".hydra-sigchld-sock";
-
-class GarbageCollector : public launchpad::Worker::Job {
- public:
- explicit GarbageCollector(pid_t pid) : pid_(pid) {}
-
- void Do() override {
- _W("pid: %d", pid_);
- _delete_sock_path(pid_, getuid());
- DeleteUnusedFiles();
- SocketGarbadgeCollector();
- }
-
- private:
- void SocketGarbadgeCollector() {
- std::string path = "/run/aul/apps/" + std::to_string(getuid());
- for (const auto &entry : fs::directory_iterator(path)) {
- if (!isdigit(entry.path().filename().string()[0]))
- continue;
-
- std::string proc_path = "/proc/" + entry.path().filename().string();
- if (access(proc_path.c_str(), F_OK) < 0) {
- _delete_sock_path(atoi(entry.path().filename().string().c_str()),
- getuid());
- }
- }
- }
-
- void DeleteUnusedFiles() {
- std::vector<std::string> files = {
- "clr-debug-pipe-" + std::to_string(pid_) + "-",
- "dotnet-diagnostic-" + std::to_string(pid_) + "-"
- };
-
- fs::path tmp_path = "/tmp";
- for (const auto &entry : fs::directory_iterator(tmp_path)) {
- if (entry.is_directory() || entry.path().filename().string()[0] == '.')
- continue;
-
- bool found = false;
- for (const auto &file : files) {
- if (entry.path().filename().string().find(file) == 0) {
- fs::remove(entry.path());
- _W("Removed file: %s", entry.path().c_str());
- found = true;
- break;
- }
- }
-
- if (!found)
- continue;
- }
- }
-
- private:
- pid_t pid_;
-};
-
-pid_t __pid;
-sigset_t __mask;
-sigset_t __old_mask;
-socket_h __sigchld_socket;
-io_channel_h __sigchld_channel;
-socket_h __hydra_sigchld_socket;
-io_channel_h __hydra_sigchld_channel;
-signal_sigchld_cb __callback;
-void* __user_data;
-
-std::unique_ptr<launchpad::Worker> recycle_bin;
-
-} // namespace
-
-static gboolean __hydra_sigchld_recovery_cb(gpointer data);
-static gboolean __sigchld_recovery_cb(gpointer data);
-
-static void __sigchld_action(int pid) {
- launchpad::DBus::SendAppDeadSignal(pid);
- recycle_bin->Add(std::make_shared<GarbageCollector>(pid));
-}
-
-static int __check_permission(int pid) {
- char buf[512] = {
- 0,
- };
- int ret;
-
- 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 bool __hydra_sigchld_handler(int fd,
- io_condition_e cond,
- void* user_data) {
- socket_h client_socket;
- int caller_pid;
- int pid = -1;
- int ret;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- g_idle_add(__hydra_sigchld_recovery_cb, nullptr);
- 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;
- }
-
- 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;
- }
-
- _W("[__SIGCHLD__] pid(%d)", pid);
- __sigchld_action(pid);
-
- if (__callback)
- __callback(pid, user_data);
-
- return true;
-}
-
-static int __hydra_sigchld_init(void) {
- char path[LAUNCHPAD_SOCKET_PATH_SIZE];
- io_channel_h channel;
- socket_h socket;
- int ret;
- int fd;
-
- snprintf(path, sizeof(path), "/run/aul/daemons/%u/%s", getuid(),
- HYDRA_SIGCHLD_SOCK);
- ret = _socket_create(path, false, &socket);
- if (ret < 0)
- return ret;
-
- _socket_get_fd(socket, &fd);
-
- auto cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
- channel = _io_channel_create(fd, static_cast<io_condition_e>(cond),
- __hydra_sigchld_handler, nullptr);
- if (!channel) {
- _socket_destroy(socket);
- return -ENOMEM;
- }
-
- _io_channel_set_close_on_destroy(channel, false);
-
- __hydra_sigchld_socket = socket;
- __hydra_sigchld_channel = channel;
-
- return 0;
-}
-
-static int __hydra_sigchld_fini(void) {
- if (__hydra_sigchld_channel)
- _io_channel_destroy(__hydra_sigchld_channel);
-
- if (__hydra_sigchld_socket) {
- if (__pid != getpid())
- _socket_set_fd(__hydra_sigchld_socket, -1);
-
- _socket_destroy(__hydra_sigchld_socket);
- }
-
- return 0;
-}
-
-static bool __sigchld_handler(int fd, io_condition_e cond, void* user_data) {
- struct signalfd_siginfo info;
- pid_t child_pid;
- pid_t child_pgid;
- int status;
- int ret;
-
- if (cond & (IO_ERR | IO_HUP | IO_NVAL)) {
- _E("fd(%d), io_condition(%d)", fd, cond);
- g_idle_add(__sigchld_recovery_cb, nullptr);
- return false;
- }
-
- do {
- ret = _socket_read(__sigchld_socket, &info, sizeof(info));
- if (ret < 0)
- break;
-
- child_pgid = getpgid(info.ssi_pid);
- _W("[__SIGCHLD__] pid(%d), pgid(%d), status(%d)", info.ssi_pid, child_pgid,
- info.ssi_status);
-
- while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
- if (child_pid == child_pgid)
- killpg(child_pgid, SIGKILL);
-
- __sigchld_action(child_pid);
- }
-
- if (__callback)
- __callback(info.ssi_pid, __user_data);
- } while (ret == 0);
-
- return true;
-}
-
-static int __signal_block_sigchld(void) {
- int ret;
-
- sigemptyset(&__mask);
- sigaddset(&__mask, SIGCHLD);
-
- ret = sigprocmask(SIG_BLOCK, &__mask, &__old_mask);
- if (ret < 0) {
- ret = -errno;
- _E("sigprocmask(SIG_BLOCK) is failed. errno(%d)", errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __signal_get_sigchld_fd(void) {
- int sfd;
-
- sfd = signalfd(-1, &__mask, SFD_NONBLOCK | SFD_CLOEXEC);
- if (sfd < 0) {
- sfd = -errno;
- _E("signalfd() is failed. errno(%d)", errno);
- return sfd;
- }
-
- return sfd;
-}
-
-int _signal_unblock_sigchld(void) {
- int ret;
-
- ret = sigprocmask(SIG_SETMASK, &__old_mask, nullptr);
- if (ret < 0) {
- ret = -errno;
- _E("sigprocmask(SIG_SETMASK) is failed. errno(%d)", errno);
- return ret;
- }
-
- return 0;
-}
-
-static int __sigchld_init(void) {
- io_channel_h channel;
- socket_h socket;
- int sfd;
- int ret;
-
- sfd = __signal_get_sigchld_fd();
- if (sfd < 0)
- return sfd;
-
- ret = _socket_create_with_fd(sfd, &socket);
- if (ret < 0) {
- close(sfd);
- return ret;
- }
-
- auto cond = IO_IN | IO_PRI | IO_ERR | IO_HUP | IO_NVAL;
- channel = _io_channel_create(sfd, static_cast<io_condition_e>(cond),
- __sigchld_handler, nullptr);
- 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 __sigchld_fini(void) {
- if (__sigchld_channel)
- _io_channel_destroy(__sigchld_channel);
-
- if (__sigchld_socket) {
- if (__pid != getpid())
- _socket_set_fd(__sigchld_socket, -1);
-
- _socket_destroy(__sigchld_socket);
- }
-
- return 0;
-}
-
-int _signal_set_sigchld_cb(signal_sigchld_cb callback, void* user_data) {
- __callback = callback;
- __user_data = user_data;
-
- return 0;
-}
-
-static gboolean __hydra_sigchld_recovery_cb(gpointer data) {
- int ret;
-
- __hydra_sigchld_fini();
-
- ret = __hydra_sigchld_init();
- if (ret < 0) {
- _E("Failed to recover hydra sigchld socket");
- abort();
- } else {
- _W("[__RECOVERY__] Hydra SIGCHLD Socket");
- }
-
- return G_SOURCE_REMOVE;
-}
-
-static gboolean __sigchld_recovery_cb(gpointer data) {
- int ret;
-
- __sigchld_fini();
-
- ret = __sigchld_init();
- if (ret < 0) {
- _E("Failed to recover sigchld fd");
- abort();
- } else {
- _W("[__RECOVERY__] SIGCHLD fd");
- }
-
- return G_SOURCE_REMOVE;
-}
-
-int _signal_init(void) {
- int ret;
- int i;
-
- _D("SIGNAL_INIT");
- __pid = getpid();
-
- ret = __signal_block_sigchld();
- if (ret < 0)
- return ret;
-
- ret = __sigchld_init();
- if (ret < 0)
- return ret;
-
- ret = __hydra_sigchld_init();
- if (ret < 0)
- return ret;
-
- for (i = 0; i < _NSIG; ++i) {
- switch (i) {
- /* controlled by sys-assert package*/
- case SIGQUIT:
- case SIGILL:
- case SIGABRT:
- case SIGBUS:
- case SIGFPE:
- case SIGSEGV:
- case SIGPIPE:
- break;
- default:
- signal(i, SIG_DFL);
- break;
- }
- }
-
- recycle_bin.reset(new launchpad::Worker("RecycleBin+"));
- return 0;
-}
-
-void _signal_fini(void) {
-#ifndef PRELOAD_ACTIVATE
- int i;
-
- for (i = 0; i < _NSIG; ++i)
- signal(i, SIG_DFL);
-#endif
-
- _D("SIGNAL_FINI");
- recycle_bin.reset();
- _signal_set_sigchld_cb(nullptr, nullptr);
- __hydra_sigchld_fini();
- __sigchld_fini();
- _signal_unblock_sigchld();
-}
+++ /dev/null
-/*
- * Copyright (c) 2016 - 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_SIGNAL_H__
-#define __LAUNCHPAD_SIGNAL_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_unblock_sigchld(void);
-
-int _signal_init(void);
-
-void _signal_fini(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LAUNCHPAD_SIGNAL_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "launchpad-process-pool/sigchld_event.hh"
+
+#include <sys/signalfd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "launchpad-process-pool/log_private.hh"
+
+namespace launchpad {
+
+SigchldEvent::SigchldEvent(int sfd, IEvent* listener)
+ : socket_(new Socket(sfd)),
+ channel_(new IOChannel(sfd, IOChannel::IOCondition::IO_IN, this)),
+ listener_(listener) {
+ _W("SigchldEvent() ctor. sfd: %d", sfd);
+ channel_->SetCloseOnDestroy(false);
+}
+
+SigchldEvent::~SigchldEvent() {
+ if (getpid() != current_pid_)
+ socket_->RemoveFd();
+}
+
+void SigchldEvent::OnIOEventReceived(int fd, int condition) {
+ struct signalfd_siginfo info;
+ pid_t child_pid;
+ int status;
+ int ret;
+
+ do {
+ ret = socket_->Read(&info, sizeof(info));
+ if (ret < 0)
+ break;
+
+ pid_t child_pgid = getpgid(info.ssi_pid);
+ _W("[SIGCHLD] pid(%d), pgid(%d), status(%d)",
+ info.ssi_pid, child_pgid, info.ssi_status);
+
+ while ((child_pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ if (child_pid == child_pgid)
+ killpg(child_pgid, SIGKILL);
+
+ if (listener_ != nullptr)
+ listener_->OnSigchld(child_pid, status);
+ }
+ } while (ret == 0);
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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_PROCESS_POOL_SIGCHLD_EVENT_HH_
+#define LAUNCHPAD_PROCESS_POOL_SIGCHLD_EVENT_HH_
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <io_channel.hh>
+#include <socket.hh>
+
+namespace launchpad {
+
+class SigchldEvent : public IOChannel::IEvent {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnSigchld(pid_t pid, int status) = 0;
+ };
+
+ SigchldEvent(int sfd, IEvent* listener);
+ virtual ~SigchldEvent();
+
+ private:
+ void OnIOEventReceived(int fd, int condition) override;
+
+ private:
+ std::unique_ptr<Socket> socket_;
+ std::unique_ptr<IOChannel> channel_;
+ IEvent* listener_;
+ pid_t current_pid_ = getpid();
+};
+
+} // namespace launchpad
+
+#endif // LAUNCHPAD_PROCESS_POOL_SIGCHLD_EVENT_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "launchpad-process-pool/signal_manager.hh"
+
+#include <sys/signalfd.h>
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "lib/common/inc/launchpad_common.h"
+
+#include "launchpad-process-pool/dbus.hh"
+#include "launchpad-process-pool/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+namespace fs = std::filesystem;
+
+class GarbageCollector : public launchpad::Worker::Job {
+ public:
+ explicit GarbageCollector(pid_t pid) : pid_(pid) {}
+
+ void Do() override {
+ _W("pid: %d", pid_);
+ _delete_sock_path(pid_, getuid());
+ DeleteUnusedFiles();
+ SocketGarbadgeCollector();
+ }
+
+ private:
+ void SocketGarbadgeCollector() {
+ std::string path = "/run/aul/apps/" + std::to_string(getuid());
+ for (const auto &entry : fs::directory_iterator(path)) {
+ if (!isdigit(entry.path().filename().string()[0]))
+ continue;
+
+ std::string proc_path = "/proc/" + entry.path().filename().string();
+ if (!fs::exists(proc_path))
+ _delete_sock_path(atoi(entry.path().filename().c_str()), getuid());
+ }
+ }
+
+ void DeleteUnusedFiles() {
+ std::vector<std::string> files = {
+ "clr-debug-pipe-" + std::to_string(pid_) + "-",
+ "dotnet-diagnostic-" + std::to_string(pid_) + "-"
+ };
+
+ fs::path tmp_path = "/tmp";
+ for (const auto &entry : fs::directory_iterator(tmp_path)) {
+ if (entry.is_directory() || entry.path().filename().string()[0] == '.')
+ continue;
+
+ bool found = false;
+ for (const auto &file : files) {
+ if (entry.path().filename().string().find(file) == 0) {
+ fs::remove(entry.path());
+ _W("Removed file: %s", entry.path().c_str());
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ continue;
+ }
+ }
+
+ private:
+ pid_t pid_;
+};
+
+} // namespace
+
+SignalManager& SignalManager::GetInst() {
+ static SignalManager inst;
+ inst.Init();
+ return inst;
+}
+
+void SignalManager::Dispose() {
+ if (disposed_)
+ return;
+
+ _W("BEGIN");
+#ifndef PRELOAD_ACTIVATE
+ for (int signo = 0; signo < _NSIG; ++signo)
+ signal(signo, SIG_DFL);
+#endif // PRELOAD_ACTIVATE
+
+ recycle_bin_.reset();
+ hydra_sigchld_event_.reset();
+ sigchld_event_.reset();
+ disposed_ = true;
+ _W("END");
+}
+
+void SignalManager::Init() {
+ if (!disposed_)
+ return;
+
+ _W("BEGIN");
+ if (BlockSigchld() != 0)
+ return;
+
+ int sfd = GetSigchldFd();
+ if (sfd < 0)
+ return;
+
+ sigchld_event_.reset(new SigchldEvent(sfd, this));
+ hydra_sigchld_event_.reset(new HydraSigchldEvent(this));
+ recycle_bin_.reset(new Worker("RecycleBin+"));
+
+ for (int signo = 0; signo < _NSIG; ++signo) {
+ if (signo == SIGQUIT ||
+ signo == SIGILL ||
+ signo == SIGABRT ||
+ signo == SIGBUS ||
+ signo == SIGFPE ||
+ signo == SIGSEGV ||
+ signo == SIGPIPE)
+ continue;
+
+ signal(signo, SIG_DFL);
+ }
+
+ disposed_ = false;
+ _W("END");
+}
+
+void SignalManager::SetEventListener(SignalManager::IEvent* listener) {
+ listener_ = listener;
+}
+
+void SignalManager::UnblockSigchld() {
+ if (sigprocmask(SIG_SETMASK, &old_mask_, nullptr) < 0)
+ _E("sigprocmask(SIG_SETMASK) is failed. errno(%d)", errno);
+}
+
+SignalManager::~SignalManager() {
+ Dispose();
+}
+
+int SignalManager::BlockSigchld() {
+ sigemptyset(&mask_);
+ sigaddset(&mask_, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &mask_, &old_mask_) < 0) {
+ int ret = -errno;
+ _E("sigprocmask(SIG_BLOCK) is failed. errno(%d)", errno);
+ return ret;
+ }
+
+ return 0;
+}
+
+int SignalManager::GetSigchldFd() {
+ int sfd = signalfd(-1, &mask_, SFD_NONBLOCK | SFD_CLOEXEC);
+ if (sfd < 0) {
+ sfd = -errno;
+ _E("signalfd() is failed. errno(%d)", errno);
+ }
+
+ return sfd;
+}
+
+void SignalManager::HandleSigchld(pid_t pid) {
+ DBus::SendAppDeadSignal(pid);
+ recycle_bin_->Add(std::make_shared<GarbageCollector>(pid));
+}
+
+void SignalManager::OnSigchld(pid_t pid, int status) {
+ _W("pid: %d, status: %d", pid, status);
+ HandleSigchld(pid);
+}
+
+void SignalManager::OnHydraSigchld(pid_t pid) {
+ _W("pid: %d", pid);
+ HandleSigchld(pid);
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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_PROCESS_POOL_SIGNAL_MANAGER_HH_
+#define LAUNCHPAD_PROCESS_POOL_SIGNAL_MANAGER_HH_
+
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <client_socket.hh>
+#include <io_channel.hh>
+#include <server_socket.hh>
+
+#include "launchpad-process-pool/hydra_sigchld_event.hh"
+#include "launchpad-process-pool/sigchld_event.hh"
+#include "launchpad-process-pool/worker.hh"
+
+namespace launchpad {
+
+class SignalManager : public SigchldEvent::IEvent,
+ public HydraSigchldEvent::IEvent {
+ public:
+ class IEvent {
+ public:
+ virtual ~IEvent() = default;
+ virtual void OnSigchldReceived(pid_t pid) = 0;
+ };
+
+ SignalManager(const SignalManager&) = delete;
+ SignalManager& operator = (const SignalManager&) = delete;
+ SignalManager(SignalManager&&) = delete;
+ SignalManager& operator = (SignalManager&&) = delete;
+
+ static SignalManager& GetInst();
+ void Dispose();
+
+ void SetEventListener(IEvent* listener);
+ void UnblockSigchld();
+
+ private:
+ SignalManager() = default;
+ ~SignalManager();
+
+ void Init();
+ void HandleSigchld(pid_t pid);
+ int GetSigchldFd();
+ int BlockSigchld();
+
+ void OnSigchld(pid_t pid, int status) override;
+ void OnHydraSigchld(pid_t pid) override;
+
+ private:
+ bool disposed_ = true;
+ IEvent* listener_ = nullptr;
+ sigset_t mask_;
+ sigset_t old_mask_;
+ std::unique_ptr<SigchldEvent> sigchld_event_;
+ std::unique_ptr<HydraSigchldEvent> hydra_sigchld_event_;
+ std::unique_ptr<Worker> recycle_bin_;
+};
+
+} // namespace launchpad
+
+#endif // LAUNCHPAD_PROCESS_POOL_SIGNAL_MANAGER_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "launchpad-common/peer_credentials.hh"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "launchpad-common/log_private.hh"
+
+namespace launchpad {
+
+pid_t PeerCredentials::GetPid() const {
+ return pid_;
+}
+
+uid_t PeerCredentials::GetUid() const {
+ return uid_;
+}
+
+gid_t PeerCredentials::GetGid() const {
+ return gid_;
+}
+
+PeerCredentials::PeerCredentials(pid_t pid, uid_t uid, gid_t gid)
+ : pid_(pid), uid_(uid), gid_(gid) {
+}
+
+std::unique_ptr<PeerCredentials> PeerCredentials::Get(int fd) {
+ struct ucred cred;
+ socklen_t len = sizeof(struct ucred);
+ int ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED,
+ static_cast<void*>(&cred), &len);
+ if (ret != 0) {
+ _E("getsockopt() is failed. fd(%d), errno(%d)", fd, errno);
+ return nullptr;
+ }
+
+ return std::make_unique<PeerCredentials>(cred.pid, cred.uid, cred.gid);
+}
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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 LIB_LAUNCHPAD_COMMON_PEER_CREDENTIALS_HH_
+#define LIB_LAUNCHPAD_COMMON_PEER_CREDENTIALS_HH_
+
+#include <sys/types.h>
+
+#include <memory>
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace launchpad {
+
+class EXPORT_API PeerCredentials {
+ public:
+ PeerCredentials(pid_t pid, uid_t uid, gid_t gid);
+ virtual ~PeerCredentials() = default;
+
+ static std::unique_ptr<PeerCredentials> Get(int fd);
+
+ pid_t GetPid() const;
+ uid_t GetUid() const;
+ gid_t GetGid() const;
+
+ private:
+ pid_t pid_;
+ uid_t uid_;
+ gid_t gid_;
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_COMMON_PEER_CREDENTIALS_HH_
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ */
+
+#include "launchpad-common/socket.hh"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "launchpad-common/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+constexpr const int MAX_RETRY_CNT = 2;
+
+} // namespace
+
+Socket::Socket(int fd) : fd_(fd) {}
+
+Socket::~Socket() {
+ Close();
+}
+
+void Socket::Close() {
+ if (fd_ > -1) {
+ close(fd_);
+ fd_ = -1;
+ }
+}
+
+int Socket::Write(const void* buf, size_t size) {
+ const unsigned char* buffer = static_cast<const unsigned char*>(buf);
+ size_t left = size;
+
+ while (left) {
+ ssize_t bytes = write(fd_, buffer, left);
+ if (bytes < 0) {
+ int ret = -errno;
+ _E("Write() is failed. fd(%d), errno(%d)", fd_, errno);
+ return ret;
+ }
+
+ left -= bytes;
+ buffer += bytes;
+ }
+
+ return 0;
+}
+
+int Socket::Read(void* buf, size_t size) {
+ unsigned char* buffer = static_cast<unsigned char*>(buf);
+ size_t left = size;
+
+ while (left) {
+ ssize_t bytes = read(fd_, buffer, left);
+ if (bytes == 0) {
+ _W("EOF. fd(%d)", fd_);
+ return -EIO;
+ }
+
+ if (bytes < 0)
+ return -errno;
+
+ left -= bytes;
+ buffer += bytes;
+ }
+
+ return 0;
+}
+
+bool Socket::IsClosed() const {
+ return fd_ < 0;
+}
+
+int Socket::GetFd() const {
+ return fd_;
+}
+
+int Socket::RemoveFd() {
+ int fd = fd_;
+ fd_ = -1;
+ return fd;
+}
+
+} // namespace launchpad
--- /dev/null
+/*
+ * Copyright (c) 2023 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 LIB_LAUNCHPAD_COMMON_SOCKET_HH_
+#define LIB_LAUNCHPAD_COMMON_SOCKET_HH_
+
+#include <exception.hh>
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace launchpad {
+
+class EXPORT_API Socket {
+ public:
+ explicit Socket(int fd);
+ virtual ~Socket();
+ Socket(const Socket&) = delete;
+ Socket& operator = (const Socket&) = delete;
+
+ void Close();
+ int Write(const void* buf, size_t size);
+ int Read(void* buf, size_t size);
+ bool IsClosed() const;
+ int GetFd() const;
+ int RemoveFd();
+
+ private:
+ int fd_;
+};
+
+} // namespace launchpad
+
+#endif // LIB_LAUNCHPAD_COMMON_SOCKET_HH_