Refactor launchpad signal 99/290099/7
authorHwankyu Jhun <h.jhun@samsung.com>
Mon, 20 Mar 2023 07:24:43 +0000 (07:24 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 21 Mar 2023 01:53:58 +0000 (01:53 +0000)
The launchpad signal is implemented using C++ language.

Change-Id: I633d2a5d58f01b4fdf70df9613fb1dbd1a2c88b2
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
13 files changed:
src/launchpad-process-pool/hydra_sigchld_event.cc [new file with mode: 0644]
src/launchpad-process-pool/hydra_sigchld_event.hh [new file with mode: 0644]
src/launchpad-process-pool/launchpad.cc
src/launchpad-process-pool/launchpad_signal.cc [deleted file]
src/launchpad-process-pool/launchpad_signal.h [deleted file]
src/launchpad-process-pool/sigchld_event.cc [new file with mode: 0644]
src/launchpad-process-pool/sigchld_event.hh [new file with mode: 0644]
src/launchpad-process-pool/signal_manager.cc [new file with mode: 0644]
src/launchpad-process-pool/signal_manager.hh [new file with mode: 0644]
src/lib/launchpad-common/peer_credentials.cc [new file with mode: 0644]
src/lib/launchpad-common/peer_credentials.hh [new file with mode: 0644]
src/lib/launchpad-common/socket.cc [new file with mode: 0644]
src/lib/launchpad-common/socket.hh [new file with mode: 0644]

diff --git a/src/launchpad-process-pool/hydra_sigchld_event.cc b/src/launchpad-process-pool/hydra_sigchld_event.cc
new file mode 100644 (file)
index 0000000..6f26dd1
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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
diff --git a/src/launchpad-process-pool/hydra_sigchld_event.hh b/src/launchpad-process-pool/hydra_sigchld_event.hh
new file mode 100644 (file)
index 0000000..cc703cd
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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_
index cb240cc..8cde2e1 100644 (file)
@@ -49,7 +49,6 @@
 #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"
@@ -61,6 +60,7 @@
 #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
@@ -202,6 +202,7 @@ typedef request_t* request_h;
 typedef int (*request_handler)(request_h request);
 
 static void HandleMemoryStatusChangedEvent(bool low_memory);
+static void HandleSigchld(pid_t pid);
 
 namespace {
 
@@ -251,6 +252,13 @@ class MemoryManager : public launchpad::MemoryMonitor,
   }
 };
 
+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;
@@ -272,6 +280,7 @@ io_channel_h __launchpad_channel;
 int __client_fd = -1;
 launchpad::AsanAppChecker __asan_app_checker;
 std::unique_ptr<launchpad::Worker> cleaner;
+SigchldHandler sigchld_handler;
 
 }  // namespace
 
@@ -841,7 +850,7 @@ static int __exec_loader_process(void* arg) {
   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]));
 
@@ -1418,8 +1427,7 @@ static int __exec_app_process(void* arg) {
     setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
   }
 
-  _signal_unblock_sigchld();
-
+  launchpad::SignalManager::GetInst().UnblockSigchld();
   _delete_sock_path(getpid(), getuid());
 
   PERF("prepare exec - first done");
@@ -1639,7 +1647,7 @@ static bool __handle_hydra_event(int fd, io_condition_e cond, void* data) {
   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) {
@@ -3328,13 +3336,7 @@ static int __before_loop(int argc, char** argv) {
     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) {
@@ -3416,7 +3418,7 @@ static void __after_loop(void) {
   if (__launchpad_channel)
     _io_channel_destroy(__launchpad_channel);
 
-  _signal_fini();
+  launchpad::SignalManager::GetInst().Dispose();
 
   __sequencer_fini();
 }
diff --git a/src/launchpad-process-pool/launchpad_signal.cc b/src/launchpad-process-pool/launchpad_signal.cc
deleted file mode 100644 (file)
index 13b6a0a..0000000
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * 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();
-}
diff --git a/src/launchpad-process-pool/launchpad_signal.h b/src/launchpad-process-pool/launchpad_signal.h
deleted file mode 100644 (file)
index dffd961..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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__ */
diff --git a/src/launchpad-process-pool/sigchld_event.cc b/src/launchpad-process-pool/sigchld_event.cc
new file mode 100644 (file)
index 0000000..b53624b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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
diff --git a/src/launchpad-process-pool/sigchld_event.hh b/src/launchpad-process-pool/sigchld_event.hh
new file mode 100644 (file)
index 0000000..56765ed
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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_
diff --git a/src/launchpad-process-pool/signal_manager.cc b/src/launchpad-process-pool/signal_manager.cc
new file mode 100644 (file)
index 0000000..943a022
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * 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
diff --git a/src/launchpad-process-pool/signal_manager.hh b/src/launchpad-process-pool/signal_manager.hh
new file mode 100644 (file)
index 0000000..23bef10
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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_
diff --git a/src/lib/launchpad-common/peer_credentials.cc b/src/lib/launchpad-common/peer_credentials.cc
new file mode 100644 (file)
index 0000000..c2ac128
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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
diff --git a/src/lib/launchpad-common/peer_credentials.hh b/src/lib/launchpad-common/peer_credentials.hh
new file mode 100644 (file)
index 0000000..5387a03
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_
diff --git a/src/lib/launchpad-common/socket.cc b/src/lib/launchpad-common/socket.cc
new file mode 100644 (file)
index 0000000..bb6c152
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * 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
diff --git a/src/lib/launchpad-common/socket.hh b/src/lib/launchpad-common/socket.hh
new file mode 100644 (file)
index 0000000..3078e96
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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_