Refactor Launchpad Library 01/293401/11
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 26 May 2023 01:15:30 +0000 (01:15 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 31 May 2023 23:52:51 +0000 (23:52 +0000)
The launchpad library is impemented using C++ language.

Change-Id: I191aca9713f8771806a2516374d0710185ab9993
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
18 files changed:
src/launchpad-process-pool/launchpad.cc
src/launchpad-process-pool/launchpad.hh
src/launchpad-process-pool/loader_context.cc
src/lib/launchpad-common/sched_priority.cc
src/lib/launchpad-common/sched_priority.hh
src/lib/launchpad-glib/language_config.cc [moved from src/launchpad-process-pool/language_config.cc with 92% similarity]
src/lib/launchpad-glib/language_config.hh [moved from src/launchpad-process-pool/language_config.hh with 85% similarity]
src/lib/launchpad-glib/region_format_config.cc [moved from src/launchpad-process-pool/region_format_config.cc with 92% similarity]
src/lib/launchpad-glib/region_format_config.hh [moved from src/launchpad-process-pool/region_format_config.hh with 75% similarity]
src/lib/launchpad/CMakeLists.txt
src/lib/launchpad/launchpad_loader.cc [new file with mode: 0644]
src/lib/launchpad/launchpad_loader.hh [new file with mode: 0644]
src/lib/launchpad/log_private.hh [new file with mode: 0644]
src/lib/launchpad/src/launchpad_lib.c [deleted file]
src/lib/launchpad/step_prepare_execution.cc [new file with mode: 0644]
src/lib/launchpad/step_prepare_execution.hh [new file with mode: 0644]
src/lib/launchpad/thread_control.cc [new file with mode: 0644]
src/lib/launchpad/thread_control.hh [new file with mode: 0644]

index 3fdb624..4e25d5b 100644 (file)
 #include "launchpad-process-pool/config.hh"
 #include "launchpad-process-pool/dbus.hh"
 #include "launchpad-process-pool/debug.hh"
-#include "launchpad-process-pool/language_config.hh"
 #include "launchpad-process-pool/launcher_info.hh"
 #include "launchpad-process-pool/launchpad_args.hh"
 #include "launchpad-process-pool/loader_manager.hh"
 #include "launchpad-process-pool/loader_executor.hh"
 #include "launchpad-process-pool/log.hh"
 #include "launchpad-process-pool/memory_monitor.hh"
-#include "launchpad-process-pool/region_format_config.hh"
 #include "launchpad-process-pool/signal_manager.hh"
 #include "launchpad-process-pool/tracer.hh"
 #include "launchpad-process-pool/user_tracer.hh"
index 477a40f..690af31 100644 (file)
 #include <unordered_map>
 #include <vector>
 
+#include <language_config.hh>
 #include <io_channel.hh>
+#include <region_format_config.hh>
 #include <server_socket.hh>
 
 #include "launchpad-process-pool/app_executor.hh"
-#include "launchpad-process-pool/language_config.hh"
-#include "launchpad-process-pool/region_format_config.hh"
 #include "launchpad-process-pool/request.hh"
 #include "launchpad-process-pool/signal_manager.hh"
 #include "launchpad-process-pool/loader_manager.hh"
index 7458bbb..8ced6a7 100644 (file)
@@ -92,17 +92,6 @@ int VerifyLoaderCaps(const std::string& executable_file) {
   return 0;
 }
 
-int SendAppPacket(ClientSocket* client_socket, app_pkt_t *app_packet) {
-  if (client_socket == nullptr || app_packet == nullptr) {
-    _E("Invalid parameter");
-    return -EINVAL;
-  }
-
-  const size_t size = sizeof(app_packet->cmd) + sizeof(app_packet->opt) +
-      sizeof(app_packet->len) + app_packet->len;
-  return client_socket->Send(static_cast<void*>(app_packet), size);
-}
-
 }  // namespace
 
 LoaderContext::Builder& LoaderContext::Builder::SetLoaderInfo(
@@ -242,9 +231,19 @@ pid_t LoaderContext::Prepare() {
 
 pid_t LoaderContext::Deploy(const AppInfo* app_info, app_pkt_t* app_packet) {
   Util::DeleteSocketPath(pid_, getuid());
-  int ret = SendAppPacket(client_socket_.get(), app_packet);
+  tizen_base::Parcel parcel;
+  parcel.WriteParcelable(*app_info);
+  size_t data_size = parcel.GetDataSize();
+  int ret = client_socket_->Send(static_cast<void*>(&data_size),
+      sizeof(data_size));
+  if (ret != 0) {
+    _E("Failed to send request. pid(%d)", pid_);
+    return ret;
+  }
+
+  ret = client_socket_->Send(parcel.GetData(), data_size);
   if (ret != 0) {
-    _E("Failed to send request to the loader. pid(%d)", pid_);
+    _E("Failed to send request. pid(%d)", pid_);
     return ret;
   }
 
index 68d5e48..19ccc91 100644 (file)
@@ -23,7 +23,7 @@
 
 namespace launchpad {
 
-void SchedPriority::Set(int priority) {
+int SchedPriority::Set(int priority) {
   int ret = setpriority(PRIO_PGRP, 0, priority);
   if (ret != 0) {
     _E("Failed to set process priority. priority(%d), errno(%d)",
@@ -31,6 +31,8 @@ void SchedPriority::Set(int priority) {
   } else {
     _D("Setting priority(%d) is sucessful", priority);
   }
+
+  return ret;
 }
 
 int SchedPriority::Get() {
index 6e8d197..5b6e58a 100644 (file)
@@ -24,7 +24,7 @@ namespace launchpad {
 
 class EXPORT_API SchedPriority {
  public:
-  static void Set(int priority);
+  static int Set(int priority);
   static int Get();
 };
 
similarity index 92%
rename from src/launchpad-process-pool/language_config.cc
rename to src/lib/launchpad-glib/language_config.cc
index 8902c7a..030fb33 100644 (file)
  * limitations under the License.
  */
 
-#include "launchpad-process-pool/language_config.hh"
+#include "launchpad-glib/language_config.hh"
 
 #include <stdlib.h>
 
-#include "launchpad-process-pool/log_private.hh"
+#include "launchpad-glib/log_private.hh"
 
 namespace launchpad {
 
similarity index 85%
rename from src/launchpad-process-pool/language_config.hh
rename to src/lib/launchpad-glib/language_config.hh
index bff07b6..e00ee65 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
-#define LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
+#ifndef LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
+#define LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
 
 #include <string>
 
@@ -39,4 +39,4 @@ class LanguageConfig : public Vconf::IEvent {
 
 }  // namespace launchpad
 
-#endif  // LAUNCHPAD_PROCESS_POOL_LANGUAGE_CONFIG_HH_
+#endif  // LIB_LAUNCHPAD_GLIB_LANGUAGE_CONFIG_HH_
  * limitations under the License.
  */
 
-#include "launchpad-process-pool/region_format_config.hh"
+#include "launchpad-glib/region_format_config.hh"
 
 #include <stdlib.h>
 
-#include "launchpad-process-pool/log_private.hh"
+#include "launchpad-glib/log_private.hh"
 
 namespace launchpad {
 
  * limitations under the License.
  */
 
-#ifndef LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
-#define LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
+#ifndef LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
+#define LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
 
 #include <string>
 
 #include <vconf.hh>
 
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
 namespace launchpad {
 
-class RegionFormatConfig : public Vconf::IEvent {
+class EXPORT_API RegionFormatConfig : public Vconf::IEvent {
  public:
   RegionFormatConfig();
 
@@ -39,4 +42,4 @@ class RegionFormatConfig : public Vconf::IEvent {
 
 }  // namespace launchpad
 
-#endif  // LAUNCHPAD_PROCESS_POOL_REGION_FORMAT_CONFIG_HH_
+#endif  // LIB_LAUNCHPAD_GLIB_REGION_FORMAT_CONFIG_HH_
index 053920b..8761499 100644 (file)
@@ -1,9 +1,10 @@
-AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/src LAUNCHPAD_SRCS)
+AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} LAUNCHPAD_SRCS)
 AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/../common/src LIB_COMMON_SRCS)
 
 ADD_LIBRARY(${TARGET_LAUNCHPAD} SHARED
   ${LAUNCHPAD_SRCS}
   ${LIB_COMMON_SRCS})
+
 SET_TARGET_PROPERTIES(${TARGET_LAUNCHPAD} PROPERTIES SOVERSION ${MAJORVER})
 SET_TARGET_PROPERTIES(${TARGET_LAUNCHPAD} PROPERTIES VERSION ${VERSION})
 
@@ -26,7 +27,8 @@ APPLY_PKG_CONFIG(${TARGET_LAUNCHPAD} PUBLIC
   TANCHOR_DEPS
 )
 
-TARGET_LINK_LIBRARIES(${TARGET_LAUNCHPAD} PUBLIC "-ldl")
+TARGET_LINK_LIBRARIES(${TARGET_LAUNCHPAD} PUBLIC
+  ${TARGET_LAUNCHPAD_COMMON} ${TARGET_LAUNCHPAD_GLIB} "-ldl")
 
 INSTALL(TARGETS ${TARGET_LAUNCHPAD} DESTINATION ${LIB_INSTALL_DIR}
   COMPONENT RuntimeLibraries)
diff --git a/src/lib/launchpad/launchpad_loader.cc b/src/lib/launchpad/launchpad_loader.cc
new file mode 100644 (file)
index 0000000..b9092af
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * 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/launchpad_loader.hh"
+
+#include <aul.h>
+#include <bundle_cpp.h>
+#include <malloc.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <app_info.hh>
+#include <client_socket.hh>
+#include <exception.hh>
+#include <parcel.hh>
+#include <sched_priority.hh>
+#include <socket.hh>
+#include <util.hh>
+
+#include "common/inc/launchpad_common.h"
+#include "common/inc/launchpad_types.h"
+#include "launchpad/log_private.hh"
+#include "launchpad/step_prepare_execution.hh"
+#include "launchpad/thread_control.hh"
+
+namespace launchpad {
+namespace {
+
+const uint32_t kMaxRetryingCount = 600;
+constexpr const char kLaunchpadLoaderSocketName[] = ".launchpad-type";
+
+tizen_base::Bundle loader_bundle;
+std::unique_ptr<LaunchpadLoader> context;
+
+}  // namespace
+
+LaunchpadLoader::LaunchpadLoader(int argc, char** argv)
+    : argc_(argc), argv_(argv) {
+  if (argc_ < 4) {
+    _E("Too few argument");
+    THROW(-EINVAL);
+  }
+
+  int is_hydra = argv_[LOADER_ARG_HYDRA][0] - '0';
+  if (is_hydra) {
+    _E("Cannot run in hydra mode");
+    THROW(-EINVAL);
+  }
+
+  loader_type_ = atoi(argv_[LOADER_ARG_TYPE]);
+  if (loader_type_ < 0 || loader_type_ >= LAUNCHPAD_TYPE_MAX) {
+    _E("Invalid argument. type: %d", loader_type_);
+    THROW(-EINVAL);
+  }
+
+  loader_id_ = atoi(argv_[LOADER_ARG_ID]);
+  _W("loader type: %d, loader id: %d", loader_type_, loader_id_);
+  context.reset(this);
+}
+
+LaunchpadLoader::~LaunchpadLoader() {
+  if (app_argv_ != nullptr) {
+    for (int i = 0; i < app_argc_; ++i)
+      free(app_argv_[i]);
+
+    free(app_argv_);
+  }
+}
+
+void LaunchpadLoader::Run(loader_lifecycle_callback_s* callback,
+    loader_adapter_s* adapter, void* user_data) {
+  if (callback == nullptr || adapter == nullptr) {
+    _E("Invalid argument");
+    THROW(-EINVAL);
+  }
+
+  if (adapter->loop_begin == nullptr || adapter->loop_quit == nullptr ||
+      adapter->add_fd == nullptr || adapter->remove_fd == nullptr) {
+    _E("Invalid argument. adapter callback is nullptr");
+    THROW(-EINVAL);
+  }
+
+  callback_ = *callback;
+  adapter_callback_ = *adapter;
+  user_data_ = user_data;
+
+  if (!OnCreate()) {
+    _E("OnCreate() returns false");
+    THROW(-1);
+  }
+
+  SchedPriority::Set(0);
+  OnAdapterLoopBegin();
+  OnTerminate();
+}
+
+void LaunchpadLoader::Quit() {
+  OnAdapterLoopQuit();
+}
+
+const tizen_base::Bundle& LaunchpadLoader::GetBundle() const {
+  return app_info_.GetBundle();
+}
+
+void LaunchpadLoader::ResetArgs() {
+  memset(argv_[LOADER_ARG_TYPE], 0, strlen(argv_[LOADER_ARG_TYPE]));
+  memset(argv_[LOADER_ARG_ID], 0, strlen(argv_[LOADER_ARG_ID]));
+  memset(argv_[LOADER_ARG_EXTRA], 0, strlen(argv_[LOADER_ARG_EXTRA]));
+}
+
+void LaunchpadLoader::WaitForThreads(int threads) {
+  uint32_t retrying_count = 0;
+
+  if (threads <= 1)
+    return;
+
+  _W("Thread count = %u", threads);
+  do {
+    int thread_count = ThreadControl::GetInst().GetCount();
+    if (thread_count >= threads) {
+      _E("Threads(%u) are ready", thread_count);
+      return;
+    }
+
+    _D("Current thread count = %u", thread_count);
+    usleep(50 * 1000);
+    retrying_count++;
+  } while (retrying_count < kMaxRetryingCount);
+  _E("Maximum retyring count exceeded");
+}
+
+int LaunchpadLoader::ConnectToLaunchpad() {
+  std::string endpoint = "/run/aul/daemons/" + std::to_string(getuid()) +
+      "/" + std::string(kLaunchpadLoaderSocketName) +
+      std::to_string(loader_type_) + "-" + std::to_string(loader_id_);
+  ClientSocket client_socket;
+  client_socket.Connect(endpoint);
+  client_socket.SetReceiveBufferSize(Socket::kSocketMaxBufferSize);
+  client_socket.SetReceiveTimeout(5000);
+
+  pid_t pid = getpid();
+  int ret = client_socket.Send(static_cast<void*>(&pid), sizeof(pid));
+  if (ret != 0) {
+    _E("Send() is failed. error: %d", ret);
+    return ret;
+  }
+
+  return client_socket.RemoveFd();
+}
+
+bool LaunchpadLoader::OnCreate() {
+  setsid();
+  tizen_base::Bundle extra(argv_[LOADER_ARG_EXTRA]);
+  ResetArgs();
+
+  if (callback_.create == nullptr) {
+    _E("create callback is nullptr");
+    return false;
+  }
+
+  int threads = 0;
+  std::string threads_str = extra.GetString("threads");
+  if (!threads_str.empty() && std::isdigit(threads_str[0])) {
+    _W("threads: %s", threads_str.c_str());
+    threads = std::stoi(threads_str);
+  }
+
+  callback_.create(extra.GetHandle(), loader_type_, user_data_);
+  aul_launch_worker_init();
+  WaitForThreads(threads);
+  malloc_trim(0);
+
+  try {
+    int fd = ConnectToLaunchpad();
+    if (fd < 0) {
+      _E("Connection to launchpad was failed. error: %d", fd);
+      return false;
+    }
+
+    OnAdapterAddFd(fd);
+  } catch (const Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return false;
+  }
+
+  language_config_.reset(new LanguageConfig());
+  region_format_config_.reset(new RegionFormatConfig());
+  return true;
+}
+
+void LaunchpadLoader::OnPrelaunch(int argc, char** argv, AppInfo* app_info) {
+  if (callback_.prelaunch) {
+    int ret = callback_.prelaunch(argc, argv, app_info->GetAppPath().c_str(),
+        app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
+        app_info->GetPkgType().c_str(), user_data_);
+    if (ret < 0) {
+      _E("prelaunch returns an error: %d", ret);
+      exit(-1);
+    }
+  }
+}
+
+void LaunchpadLoader::DefaultLaunch(AppInfo* app_info) {
+  StepPrepareExecution step_prepare_execution;
+  if (step_prepare_execution.Prepare(app_info) != 0) {
+    _E("Failed to prepare execution");
+    exit(-1);
+  }
+}
+
+void LaunchpadLoader::ChangeArgs(int argc, char** argv) {
+  auto* env = getenv("TIZEN_LOADER_ARGS");
+  if (env != nullptr) {
+    auto* loader_args = reinterpret_cast<char*>(strtoul(env, nullptr, 10));
+    if (loader_args != nullptr)
+      argv_[0] = loader_args;
+  }
+
+  memset(argv_[0], '\0', strlen(argv_[0]));
+  snprintf(argv_[0], LOADER_ARG_LEN, "%s", argv[0]);
+}
+
+int LaunchpadLoader::OnLaunch(int argc, char** argv, AppInfo* app_info) {
+  if (callback_.launch == nullptr)
+    return -1;
+
+  return callback_.launch(argc, argv, app_info->GetAppPath().c_str(),
+      app_info->GetAppId().c_str(), app_info->GetPkgId().c_str(),
+      app_info->GetPkgType().c_str(), user_data_);
+}
+
+void LaunchpadLoader::OnTerminate() {
+  _W("Terminating...");
+  region_format_config_.reset();
+  language_config_.reset();
+
+  if (callback_.terminate != nullptr) {
+    int ret = callback_.terminate(app_argc_, app_argv_, user_data_);
+    if (ret != 0)
+      exit(ret);
+  }
+}
+
+void LaunchpadLoader::OnAdapterLoopBegin() {
+  _W("Loop begin");
+  adapter_callback_.loop_begin(user_data_);
+}
+
+void LaunchpadLoader::OnAdapterLoopQuit() {
+  _W("Loop quit");
+  adapter_callback_.loop_quit(user_data_);
+}
+
+void LaunchpadLoader::OnAdapterAddFd(int fd) {
+  _W("Add fd: %d", fd);
+  adapter_callback_.add_fd(user_data_, fd, ReceiverCb);
+}
+
+void LaunchpadLoader::OnAdapterRemovefd(int fd) {
+  _W("Remove fd: %d", fd);
+  adapter_callback_.remove_fd(user_data_, fd);
+}
+
+void LaunchpadLoader::HandleReceiverEvent(int fd) {
+  _D("fd: %d", fd);
+  ClientSocket socket(fd);
+  size_t data_size = 0;
+  int ret = socket.Receive(static_cast<void*>(&data_size), sizeof(data_size));
+  if (ret != 0) {
+    _E("Failed to receive the data from socket. error(%d)", ret);
+    return;
+  }
+
+  std::vector<uint8_t> data(data_size);
+  ret = socket.Receive(data.data(), data.size());
+  if (ret != 0) {
+    _E("Failed to receive the data from socket. error(%d)", ret);
+    return;
+  }
+
+  tizen_base::Parcel parcel(data.data(), data.size());
+  OnAdapterRemovefd(fd);
+
+  ProcessLaunchRequest(&parcel);
+  if (ret >= 0)
+    Quit();
+}
+
+void LaunchpadLoader::ReceiverCb(int fd) {
+  context->HandleReceiverEvent(fd);
+}
+
+void LaunchpadLoader::ProcessLaunchRequest(tizen_base::Parcel* parcel) {
+  parcel->ReadParcelable(&app_info_);
+  SECURE_LOGD("App Id: %s, Package Id: %s, Loader Type: %d",
+      app_info_.GetAppId().c_str(), app_info_.GetPkgId().c_str(), loader_type_);
+  if (app_info_.GetAppPath().empty() || app_info_.GetAppPath()[0] != '/') {
+    _E("AppPath is not absolute path");
+    exit(-1);
+  }
+
+  Util::SetEnvironments(&app_info_);
+  auto exported_args = app_info_.GetBundle().Export();
+  exported_args[0] = app_info_.GetAppPath();
+  app_argc_ = exported_args.size();
+  app_argv_ = static_cast<char**>(calloc(app_argc_, sizeof(char*)));
+  if (app_argv_ == nullptr) {
+    _E("calloc() is failed");
+    exit(-ENOMEM);
+  }
+
+  for (int i = 0; i < app_argc_; ++i) {
+    app_argv_[i] = strdup(exported_args[i].c_str());
+    if (app_argv_[i] == nullptr) {
+      _E("strdup() is failed. [%d] %s", i, exported_args[i].c_str());
+      exit(-ENOMEM);
+    }
+
+    SECURE_LOGD("Input argument %d : %s##", i, app_argv_[i]);
+  }
+
+  OnPrelaunch(app_argc_, app_argv_, &app_info_);
+  DefaultLaunch(&app_info_);
+  OnLaunch(app_argc_, app_argv_, &app_info_);
+  ChangeArgs(app_argc_, app_argv_);
+}
+
+}  // namespace launchpad
+
+using namespace launchpad;
+
+extern "C" EXPORT_API bundle* launchpad_loader_get_bundle(void) {
+  if (!::context)
+    return nullptr;
+
+  return ::context->GetBundle().GetHandle();
+}
+
+extern "C" EXPORT_API int launchpad_loader_main(int argc, char** argv,
+    loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
+    void* user_data) {
+  try {
+    LaunchpadLoader loader(argc, argv);
+    loader.Run(callback, adapter, user_data);
+  } catch (const Exception& e) {
+    _E("Exception occurs. error: %s", e.what());
+    return e.GetErrorCode();
+  }
+
+  return 0;
+}
+
+extern "C" EXPORT_API int launchpad_loader_set_priority(int prio) {
+  return SchedPriority::Set(prio);
+}
+
+extern "C" EXPORT_API int launchpad_loader_block_threads(void) {
+  return ThreadControl::GetInst().BlockThreads();
+}
+
+extern "C" EXPORT_API int launchpad_loader_unblock_threads(void) {
+  return ThreadControl::GetInst().UnblockThreads();
+}
diff --git a/src/lib/launchpad/launchpad_loader.hh b/src/lib/launchpad/launchpad_loader.hh
new file mode 100644 (file)
index 0000000..6e77eaa
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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_LAUNCHPAD_LOADER_HH_
+#define LIB_LAUNCHPAD_LAUNCHPAD_LOADER_HH_
+
+#include <bundle_cpp.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <app_info.hh>
+#include <language_config.hh>
+#include <parcel.hh>
+#include <region_format_config.hh>
+
+#include "inc/launchpad.h"
+
+namespace launchpad {
+
+class LaunchpadLoader {
+ public:
+  LaunchpadLoader(int argc, char** argv);
+  virtual ~LaunchpadLoader();
+
+  void Run(loader_lifecycle_callback_s* callback, loader_adapter_s* adapter,
+      void* user_data);
+  void Quit();
+  const tizen_base::Bundle& GetBundle() const;
+
+ private:
+  void WaitForThreads(int threads);
+  int ConnectToLaunchpad();
+  void DefaultLaunch(AppInfo* app_info);
+  void ResetArgs();
+  void ChangeArgs(int argc, char** argv);
+
+  bool OnCreate();
+  void OnPrelaunch(int argc, char** argv, AppInfo* app_info);
+  int OnLaunch(int argc, char** argv, AppInfo* app_info);
+  void OnTerminate();
+
+  void OnAdapterLoopBegin();
+  void OnAdapterLoopQuit();
+  void OnAdapterAddFd(int fd);
+  void OnAdapterRemovefd(int fd);
+
+  void HandleReceiverEvent(int fd);
+  void ProcessLaunchRequest(tizen_base::Parcel* parcel);
+  static void ReceiverCb(int fd);
+
+ private:
+  int argc_;
+  char** argv_;
+  int loader_type_;
+  int loader_id_;
+  loader_lifecycle_callback_s callback_ = { nullptr, };
+  loader_adapter_s adapter_callback_ = { nullptr, };
+  void* user_data_ = nullptr;
+  AppInfo app_info_;
+  std::unique_ptr<LanguageConfig> language_config_;
+  std::unique_ptr<RegionFormatConfig> region_format_config_;
+  int app_argc_ = 0;
+  char** app_argv_ = nullptr;
+};
+
+}  // namespace launchpad
+
+#endif  // LIB_LAUNCHPAD_LAUNCHPAD_LOADER_HH_
diff --git a/src/lib/launchpad/log_private.hh b/src/lib/launchpad/log_private.hh
new file mode 100644 (file)
index 0000000..8514d5e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_LOG_PRIVATE_HH_
+#define LIB_LAUNCHPAD_LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#undef LOG_TAG
+#define LOG_TAG "LIB_LAUNCHPAD"
+
+#undef _E
+#define _E LOGE
+
+#undef _W
+#define _W LOGW
+
+#undef _I
+#define _I LOGI
+
+#undef _D
+#define _D LOGD
+
+#endif  // LIB_LAUNCHPAD_LOG_PRIVATE_HH_
diff --git a/src/lib/launchpad/src/launchpad_lib.c b/src/lib/launchpad/src/launchpad_lib.c
deleted file mode 100644 (file)
index 4df635d..0000000
+++ /dev/null
@@ -1,703 +0,0 @@
-/*
- * Copyright (c) 2015 - 2019 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 <dirent.h>
-#include <malloc.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <bundle_internal.h>
-#include <aul.h>
-#include <security-manager.h>
-#include <trust-anchor.h>
-#include <buxton2.h>
-#include <vconf.h>
-
-#include "launchpad.h"
-#include "launchpad_common.h"
-#include "launchpad_types.h"
-#include "preexec.h"
-
-#ifndef API
-#define API __attribute__ ((visibility("default")))
-#endif
-
-#define AUL_PR_NAME 16
-#define SIGRTINT (SIGRTMIN + 2)
-
-typedef struct thread_handler_s {
-       struct sigaction old;
-       GMutex mutex;
-       GCond cond;
-       gint count;
-       gint num;
-       bool blocked;
-       bool done;
-} thread_handler_t;
-
-static loader_lifecycle_callback_s *__loader_callbacks;
-static loader_adapter_s *__loader_adapter;
-static void *__loader_user_data;
-static int __argc;
-static char **__argv;
-static bundle *__bundle;
-static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
-static int __loader_id;
-static bool __loop_quit;
-static thread_handler_t __thread_handler;
-
-static void __at_exit_to_release_bundle(void)
-{
-       if (__bundle)
-               bundle_free(__bundle);
-}
-
-static int __prepare_exec(const char *appid, const char *app_path,
-                       const char *pkg_type, int type, const char* pkgid,
-                       const char *root_path, bool global, bundle *kb)
-{
-       const char *file_name = NULL;
-       const char *enabled_light_user;
-       char process_name[AUL_PR_NAME] = { 0, };
-       int ret;
-       struct buxton_client *bxt_cli;
-
-       __preexec_run(pkg_type, appid, app_path);
-
-       ret = _enable_external_pkg(kb, pkgid, global ? GLOBAL_USER : getuid());
-       if (ret < 0)
-               return -1;
-
-       /* SET PRIVILEGES*/
-       SECURE_LOGD("[candidate] appid : %s / pkg_type : %s / app_path : %s",
-               appid, pkg_type, app_path);
-
-       if (global)
-               ret = trust_anchor_launch(pkgid, GLOBAL_USER);
-       else
-               ret = trust_anchor_launch(pkgid, getuid());
-
-       if (ret != TRUST_ANCHOR_ERROR_NONE &&
-                       ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
-               _E("trust_anchor_launch() returns %d", ret);
-               return -1;
-       }
-
-       ret = _mount_res_dir(root_path, kb);
-       if (ret < 0)
-               return -1;
-
-       enabled_light_user = bundle_get_val(kb, AUL_K_ENABLED_LIGHT_USER);
-       _W("security_manager_prepare_app2 ++ %s", appid);
-       ret = security_manager_prepare_app2(appid, enabled_light_user);
-       _W("security_manager_prepare_app2 -- %s", appid);
-       if (ret != SECURITY_MANAGER_SUCCESS) {
-               _E("Failed to set privileges %s:%d", appid, ret);
-               return -1;
-       }
-
-       _setup_stdio(basename(app_path));
-
-       ret = buxton_open(&bxt_cli, NULL, NULL);
-       if (ret != 0) {
-               _E("buxton_open() failed, errno(%d)", errno);
-               return -1;
-       }
-       ret = buxton_update_client_label_sync(bxt_cli);
-       if (ret != 0) {
-               _E("buxton_update_client_label() failed, errno(%d)", errno);
-               buxton_close(bxt_cli);
-               return -1;
-       }
-       buxton_close(bxt_cli);
-
-       /*
-        * SET DUMPABLE - for coredump
-        * This dumpable flag should be set after
-        * calling perm_app_set_privilege().
-        */
-       prctl(PR_SET_DUMPABLE, 1);
-
-       /* SET PROCESS NAME*/
-       if (app_path == NULL) {
-               _D("app_path should not be NULL - check menu db");
-               return -1;
-       }
-
-       file_name = strrchr(app_path, '/');
-       if (file_name == NULL) {
-               _D("file_name is NULL");
-               return -1;
-       }
-
-       file_name++;
-       if (*file_name == '\0') {
-               _D("can't locate file name to execute");
-               return -1;
-       }
-
-       memset(process_name, '\0', AUL_PR_NAME);
-       snprintf(process_name, AUL_PR_NAME, "%s", file_name);
-       prctl(PR_SET_NAME, process_name);
-
-       ret = _wait_tep_mount(kb);
-       if (ret < 0)
-               return -1;
-
-       ret = _prepare_app_socket();
-       if (ret < 0)
-               return -1;
-
-       ret = _prepare_id_file();
-       if (ret < 0)
-               return -1;
-
-       _send_cmd_to_amd(APP_STARTUP_SIGNAL);
-       return 0;
-}
-
-static int __default_launch_cb(bundle *kb, const char *appid,
-               const char *app_path, const char *root_path,
-               const char *pkgid, const char *pkg_type, int loader_type, bool global)
-{
-       char err_str[MAX_LOCAL_BUFSZ] = { 0, };
-       int r;
-
-       r = __prepare_exec(appid, app_path, pkg_type, loader_type, pkgid,
-                       root_path, global, kb);
-       if (r < 0) {
-               _E("__candidate_process_prepare_exec() failed");
-               if (access(app_path, F_OK | R_OK)) {
-                       SECURE_LOGE("access() failed for file: \"%s\", " \
-                               "error: %d (%s)", app_path, errno,
-                               strerror_r(errno, err_str, sizeof(err_str)));
-               }
-               exit(-1);
-       }
-
-       return 0;
-}
-
-static int __candidate_process_launchpad_main_loop(app_pkt_t *pkt,
-               char *out_app_path, int *out_argc, char ***out_argv, int type)
-{
-       bundle *kb;
-       appinfo_t *menu_info = NULL;
-       const char *app_path = NULL;
-       int tmp_argc = 0;
-       char **tmp_argv = NULL;
-       const char *env;
-       char *loader_args = NULL;
-       int ret = -1;
-       int i;
-
-       kb = bundle_decode(pkt->data, pkt->len);
-       if (!kb) {
-               _E("bundle decode error");
-               exit(-1);
-       }
-
-       if (__bundle != NULL)
-               bundle_free(__bundle);
-
-       __bundle = kb;
-       atexit(__at_exit_to_release_bundle);
-
-       menu_info = _appinfo_create(kb);
-       if (menu_info == NULL) {
-               _D("such pkg no found");
-               exit(-1);
-       }
-
-       if (menu_info->appid == NULL) {
-               _E("Unable to get app_id");
-               exit(-1);
-       }
-
-       if (type < 0) {
-               _E("Invalid launchpad type: %d", type);
-               exit(-1);
-       }
-
-       SECURE_LOGD("app id: %s, launchpad type: %d", menu_info->appid, type);
-
-       app_path = _appinfo_get_app_path(menu_info);
-       if (app_path == NULL) {
-               _E("app_path is NULL");
-               exit(-1);
-       }
-
-       if (app_path[0] != '/') {
-               _E("app_path is not absolute path");
-               exit(-1);
-       }
-
-       _modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info,
-                       pkt->cmd);
-
-       if (menu_info->pkgid == NULL) {
-               _E("unable to get pkg_id from menu_info");
-               exit(-1);
-       }
-
-       SECURE_LOGD("pkg id: %s", menu_info->pkgid);
-
-       /* Set environments */
-       _set_env(menu_info, kb);
-
-       tmp_argv = _create_argc_argv(kb, &tmp_argc);
-
-       if (__loader_callbacks->prelaunch) {
-               ret = __loader_callbacks->prelaunch(tmp_argc, tmp_argv,
-                               app_path, menu_info->appid, menu_info->pkgid,
-                               menu_info->pkg_type, __loader_user_data);
-
-               if (ret < 0) {
-                       _E("prelaunch callback fail (%d)", ret);
-                       exit(-1);
-               }
-       }
-
-       __default_launch_cb(kb, menu_info->appid, app_path,
-                       menu_info->root_path, menu_info->pkgid,
-                       menu_info->pkg_type, type, menu_info->global);
-
-       if (__loader_callbacks->launch) {
-               ret = __loader_callbacks->launch(tmp_argc, tmp_argv, app_path,
-                               menu_info->appid, menu_info->pkgid,
-                               menu_info->pkg_type, __loader_user_data);
-       }
-
-       if (out_app_path != NULL && out_argc != NULL && out_argv != NULL) {
-               env = getenv("TIZEN_LOADER_ARGS");
-               if (env != NULL) {
-                       loader_args = (char *)strtoul(env, NULL, 10);
-                       if (loader_args != NULL)
-                               out_app_path = loader_args;
-               }
-
-               memset(out_app_path, '\0', strlen(out_app_path));
-               snprintf(out_app_path, LOADER_ARG_LEN, "%s", app_path);
-
-               *out_argv = tmp_argv;
-               *out_argc = tmp_argc;
-               (*out_argv)[LOADER_ARG_PATH] = out_app_path;
-
-               for (i = 0; i < *out_argc; i++) {
-                       SECURE_LOGD("input argument %d : %s##", i,
-                                       (*out_argv)[i]);
-               }
-       } else {
-               exit(-1);
-       }
-
-       if (menu_info != NULL)
-               _appinfo_free(menu_info);
-
-       if (__bundle) {
-               bundle_free(__bundle);
-               __bundle = NULL;
-       }
-
-       return ret;
-}
-
-static void __receiver_cb(int fd)
-{
-       int ret = -1;
-       app_pkt_t *pkt;
-
-       _D("[candidate] ECORE_FD_READ");
-       pkt = _recv_pkt_raw(fd);
-       if (!pkt) {
-               _D("[candidate] _recv_pkt_raw error!");
-               exit(-1);
-       }
-
-       __loader_adapter->remove_fd(__loader_user_data, fd);
-       close(fd);
-       ret = __candidate_process_launchpad_main_loop(pkt,
-                       __argv[LOADER_ARG_PATH], &__argc, &__argv,
-                       __loader_type);
-       SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d",
-                       __argv[LOADER_ARG_PATH], __argc);
-       free(pkt);
-
-       if (ret >= 0) {
-               __loader_adapter->loop_quit(__loader_user_data);
-               _D("[candidate] ecore main loop quit");
-               __loop_quit = true;
-       }
-}
-
-static void __update_lang(keynode_t *node, void *user_data)
-{
-       char *lang;
-
-       lang = vconf_keynode_get_str(node);
-       if (!lang) {
-               _E("Failed to get language");
-               return;
-       }
-
-       setenv("LANG", lang, 1);
-}
-
-static void __region_format_changed_cb(keynode_t *node, void *user_data)
-{
-       char *region;
-
-       region = vconf_keynode_get_str(node);
-       if (!region) {
-               _E("Failed to get regionformat");
-               return;
-       }
-
-       setenv("LC_CTYPE", region, 1);
-}
-
-#ifndef USE_STATUS
-static unsigned int __get_thread_count(void)
-{
-       DIR *dp;
-       struct dirent *dentry;
-       unsigned int count = 0;
-
-       dp = opendir("/proc/self/task");
-       if (dp == NULL) {
-               _E("opendir() is failed. errno(%d)", errno);
-               return 0;
-       }
-
-       while ((dentry = readdir(dp)) != NULL) {
-               if (!isdigit(dentry->d_name[0]))
-                       continue;
-
-               count++;
-       }
-
-       closedir(dp);
-       return count;
-}
-#else
-static unsigned int __get_thread_count(void)
-{
-       unsigned int count = 0;
-       char line[LINE_MAX];
-       FILE *fp;
-
-       fp = fopen("/proc/self/status", "r");
-       if (fp == NULL) {
-               _E("fopen() is failed");
-               return 0;
-       }
-
-       while (fgets(line, sizeof(line), fp)) {
-               if (sscanf(line, "Threads: %u", &count) == 1)
-                       break;
-       }
-
-       fclose(fp);
-       return count;
-}
-#endif
-
-static void __wait_for_threads(unsigned int threads)
-{
-#define MAX_RETRYING_COUNT 600
-       unsigned int thread_count;
-       unsigned int retrying_count = 0;
-
-       if (threads <= 1)
-               return;
-
-       _W("Thread count = %u", threads);
-       do {
-               thread_count = __get_thread_count();
-               if (thread_count >= threads) {
-                       _E("Threads(%u) are ready", thread_count);
-                       return;
-               }
-
-               _D("Current thread count = %u", thread_count);
-               usleep(50 * 1000);
-               retrying_count++;
-       } while (retrying_count < MAX_RETRYING_COUNT);
-       _E("Maximum retrying count exceeded");
-}
-
-static int __before_loop(int argc, char **argv)
-{
-       int client_fd;
-       int ret = -1;
-       bundle *extra = NULL;
-       const char *val;
-       unsigned int threads = 0;
-       int r;
-
-       if (_verify_proc_caps() < 0)
-               return -1;
-
-       __preexec_init(argc, argv);
-
-       /* Set new session ID & new process group ID*/
-       /* In linux, child can set new session ID without check permission */
-       /* TODO : should be add to check permission in the kernel*/
-       setsid();
-
-       memset(argv[LOADER_ARG_TYPE], 0, strlen(argv[LOADER_ARG_TYPE]));
-       memset(argv[LOADER_ARG_ID], 0, strlen(argv[LOADER_ARG_ID]));
-       if (argc > 3) {
-               extra = bundle_decode((bundle_raw *)argv[LOADER_ARG_EXTRA],
-                               strlen(argv[LOADER_ARG_EXTRA]));
-               memset(argv[LOADER_ARG_EXTRA], 0,
-                               strlen(argv[LOADER_ARG_EXTRA]));
-       }
-
-       if (__loader_callbacks->create) {
-               val = bundle_get_val(extra, "threads");
-               if (val && isdigit(val[0])) {
-                       _D("threads: %s", val);
-                       threads = atoi(val);
-               }
-
-               __loader_callbacks->create(extra, __loader_type,
-                               __loader_user_data);
-               ret = 0;
-               aul_launch_worker_init();
-               __wait_for_threads(threads);
-       }
-
-       if (extra)
-               bundle_free(extra);
-
-       malloc_trim(0);
-
-       client_fd = _connect_to_launchpad(__loader_type, __loader_id);
-       if (client_fd == -1) {
-               _D("Connecting to candidate process was failed.");
-               return -1;
-       }
-
-       __loader_adapter->add_fd(__loader_user_data, client_fd, __receiver_cb);
-
-       r = vconf_notify_key_changed(VCONFKEY_LANGSET, __update_lang, NULL);
-       if (r != VCONF_OK)
-               _E("Failed to register callback for langset. error(%d)", r);
-
-       r = vconf_notify_key_changed(VCONFKEY_REGIONFORMAT,
-                       __region_format_changed_cb, NULL);
-       if (r != VCONF_OK)
-               _E("Failed to register callback for regionformat. error(%d)", r);
-
-       return ret;
-}
-
-static int __after_loop(void)
-{
-       vconf_ignore_key_changed(VCONFKEY_REGIONFORMAT,
-                       __region_format_changed_cb);
-       vconf_ignore_key_changed(VCONFKEY_LANGSET, __update_lang);
-
-       if (__loader_callbacks->terminate) {
-               return __loader_callbacks->terminate(__argc, __argv,
-                               __loader_user_data);
-       }
-
-       return -1;
-}
-
-API bundle *launchpad_loader_get_bundle(void)
-{
-       return __bundle;
-}
-
-API int launchpad_loader_main(int argc, char **argv,
-               loader_lifecycle_callback_s *callbacks,
-               loader_adapter_s *adapter, void *user_data)
-{
-       int is_hydra;
-
-       if (argc < 4) {
-               _E("too few argument.");
-               return -1;
-       }
-
-       is_hydra = argv[LOADER_ARG_HYDRA][0] - '0';
-
-       if (is_hydra) {
-               _D("Cannot run in hydra mode");
-               return -1;
-       }
-
-       __loader_type = atoi(argv[LOADER_ARG_TYPE]);
-       if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
-               _E("invalid argument. (type: %d)", __loader_type);
-               return -1;
-       }
-
-       __loader_id = atoi(argv[LOADER_ARG_ID]);
-
-       if (callbacks == NULL) {
-               _E("invalid argument. callback is null");
-               return -1;
-       }
-
-       if (adapter == NULL) {
-               _E("invalid argument. adapter is null");
-               return -1;
-       }
-
-       if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
-               || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
-               _E("invalid argument. adapter callback is null");
-               return -1;
-       }
-
-       __loader_callbacks = callbacks;
-       __loader_adapter = adapter;
-       __loader_user_data = user_data;
-       __argc = argc;
-       __argv = argv;
-
-       if (__before_loop(argc, argv) != 0) {
-               _E("Failed to prepare running loader. type(%d)", __loader_type);
-               return -1;
-       }
-
-       _set_priority(0);
-       _D("[candidate] ecore main loop begin");
-       __loader_adapter->loop_begin(__loader_user_data);
-
-       if (!__loop_quit) {
-               _E("[candidate] loop was stopped forcedly");
-               return -1;
-       }
-
-       return __after_loop();
-}
-
-API int launchpad_loader_set_priority(int prio)
-{
-       return _set_priority(prio);
-}
-
-static void __signal_handler(int signo)
-{
-       _D("Block thread");
-       g_mutex_lock(&__thread_handler.mutex);
-       g_atomic_int_set(&__thread_handler.count,
-                       g_atomic_int_get(&__thread_handler.count) - 1);
-       while (!__thread_handler.done)
-               g_cond_wait(&__thread_handler.cond, &__thread_handler.mutex);
-       g_mutex_unlock(&__thread_handler.mutex);
-       g_atomic_int_inc(&__thread_handler.count);
-       _D("Unblock thread");
-}
-
-API int launchpad_loader_block_threads(void)
-{
-       struct sigaction act;
-       struct dirent *dentry;
-       DIR *dp;
-       pid_t pid = getpid();
-       pid_t tid;
-       gint i;
-
-       if (__thread_handler.blocked) {
-               _D("Already blocked");
-               return 0;
-       }
-
-       g_mutex_init(&__thread_handler.mutex);
-       g_cond_init(&__thread_handler.cond);
-
-       memset(&act, '\0', sizeof(act));
-       sigemptyset(&act.sa_mask);
-       act.sa_flags = SA_RESTART;
-       act.sa_handler = __signal_handler;
-
-       if (sigaction(SIGRTINT, &act, &__thread_handler.old) != 0) {
-               _E("sigaction() is failed. errno(%d)", errno);
-               return -1;
-       }
-
-       __thread_handler.done = false;
-       __thread_handler.count = 0;
-       __thread_handler.num = 0;
-
-       dp = opendir("/proc/self/task");
-       if (dp == NULL) {
-               _E("opendir() is failed. errno(%d)", errno);
-               sigaction(SIGRTINT, &__thread_handler.old, NULL);
-               return -1;
-       }
-
-       while ((dentry = readdir(dp)) != NULL) {
-               if (!isdigit(dentry->d_name[0]))
-                       continue;
-
-               tid = atoi(dentry->d_name);
-               if (tid != pid) {
-                       _D("Send signal to thread(%d)", tid);
-                       if (tgkill(pid, tid, SIGRTINT) != 0) {
-                               _E("tgkill() is failed. errno(%d)", errno);
-                       } else {
-                               g_atomic_int_inc(&__thread_handler.count);
-                               __thread_handler.num++;
-                       }
-               }
-       }
-       closedir(dp);
-
-       for (i = 1000; g_atomic_int_get(&__thread_handler.count) && i; --i)
-               usleep(2000);
-
-       __thread_handler.blocked = true;
-
-       return 0;
-}
-
-API int launchpad_loader_unblock_threads(void)
-{
-       gint i;
-
-       if (!__thread_handler.blocked)
-               return 0;
-
-       g_mutex_lock(&__thread_handler.mutex);
-       __thread_handler.done = true;
-       g_cond_broadcast(&__thread_handler.cond);
-       g_mutex_unlock(&__thread_handler.mutex);
-
-       for (i = 1000; g_atomic_int_get(&__thread_handler.count) != __thread_handler.num && i; --i)
-               usleep(2000);
-
-       sigaction(SIGRTINT, &__thread_handler.old, NULL);
-       g_mutex_clear(&__thread_handler.mutex);
-       g_cond_clear(&__thread_handler.cond);
-       __thread_handler.blocked = false;
-
-       return 0;
-}
diff --git a/src/lib/launchpad/step_prepare_execution.cc b/src/lib/launchpad/step_prepare_execution.cc
new file mode 100644 (file)
index 0000000..144a086
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * 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/step_prepare_execution.hh"
+
+#include <aul.h>
+#include <bundle_cpp.h>
+#include <bundle_internal.h>
+#include <buxton2.h>
+#include <security-manager.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <trust-anchor.h>
+#include <unistd.h>
+#include <vconf.h>
+
+#include <app_info.hh>
+#include <aul_keys.hh>
+
+#include "common/inc/launchpad_common.h"
+#include "common/inc/launchpad_types.h"
+#include "launchpad/log_private.hh"
+
+namespace launchpad {
+
+StepPrepareExecution::StepPrepareExecution() {
+  steps_ = {
+    std::bind(&StepPrepareExecution::EnableExternalPackage, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::TrustAnchorLaunch, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::MountResourceDirectories, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::SecurityManagerPrepareApp, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::SetupStdio, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::BuxtonUpdateClientLabel, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::SetDumpable, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::SetProcessName, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::WaitTepMount, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::PrepareAppSocket, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::PrepareIdFile, this,
+        std::placeholders::_1),
+    std::bind(&StepPrepareExecution::SendStartupSignal, this,
+        std::placeholders::_1),
+  };
+}
+
+int StepPrepareExecution::Prepare(AppInfo* app_info) {
+  for (auto& step : steps_) {
+    if (step(app_info) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::EnableExternalPackage(AppInfo* app_info) {
+  int ret = _enable_external_pkg(app_info->GetBundle().GetHandle(),
+      app_info->GetPkgId().c_str(),
+      app_info->IsGlobal() ? GLOBAL_USER : getuid());
+  if (ret < 0) {
+    _E("Failed to enable external package. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::TrustAnchorLaunch(AppInfo* app_info) {
+  int ret = trust_anchor_launch(app_info->GetPkgId().c_str(),
+      app_info->IsGlobal() ? GLOBAL_USER : getuid());
+  if (ret != TRUST_ANCHOR_ERROR_NONE &&
+      ret != TRUST_ANCHOR_ERROR_NOT_INSTALLED) {
+    _E("trust_anchor_launch() is failed. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::MountResourceDirectories(AppInfo* app_info) {
+  int ret = _mount_res_dir(app_info->GetRootPath().c_str(),
+      app_info->GetBundle().GetHandle());
+  if (ret < 0) {
+    _E("Failed to mount resource direstories. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::SecurityManagerPrepareApp(AppInfo* app_info) {
+  auto* enabled_light_user = bundle_get_val(app_info->GetBundle().GetHandle(),
+      kAulEnabledLightUser);
+  _W("security_manager_prepare_app2() ++ %s", app_info->GetAppId().c_str());
+  int ret = security_manager_prepare_app2(app_info->GetAppId().c_str(),
+      enabled_light_user);
+  _W("security_manager_prepare_app2() -- %s", app_info->GetAppId().c_str());
+  if (ret != SECURITY_MANAGER_SUCCESS) {
+    _E("security_manager_prepare_app2() is failed. appid: %s, error: %d",
+        app_info->GetAppId().c_str(), ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::SetupStdio(AppInfo* app_info) {
+  _setup_stdio(basename(app_info->GetAppPath().c_str()));
+  return 0;
+}
+
+int StepPrepareExecution::BuxtonUpdateClientLabel(AppInfo* app_info) {
+  struct buxton_client* client = nullptr;
+  int ret = buxton_open(&client, nullptr, nullptr);
+  if (ret != 0) {
+    _E("buxton_open() is failed. errno: %d", errno);
+    return -1;
+  }
+
+  ret = buxton_update_client_label_sync(client);
+  buxton_close(client);
+  if (ret != 0) {
+    _E("buxton_update_client_label_sync() is failed. errno: %d", errno);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::SetDumpable(AppInfo* app_info) {
+  prctl(PR_SET_DUMPABLE, 1);
+  return 0;
+}
+
+int StepPrepareExecution::SetProcessName(AppInfo* app_info) {
+  char process_name[16] = { 0, };
+  snprintf(process_name, sizeof(process_name), "%s",
+      basename(app_info->GetAppPath().c_str()));
+  prctl(PR_SET_NAME, process_name);
+  return 0;
+}
+
+int StepPrepareExecution::WaitTepMount(AppInfo* app_info) {
+  int ret = _wait_tep_mount(app_info->GetBundle().GetHandle());
+  if (ret < 0) {
+    _E("Failed to wait tep mount. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::PrepareAppSocket(AppInfo* app_info) {
+  int ret = _prepare_app_socket();
+  if (ret < 0) {
+    _E("Failed to prepare app socket. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::PrepareIdFile(AppInfo* app_info) {
+  int ret = _prepare_id_file();
+  if (ret < 0) {
+    _E("Failed to prepare id file. error: %d", ret);
+    return -1;
+  }
+
+  return 0;
+}
+
+int StepPrepareExecution::SendStartupSignal(AppInfo* app_info) {
+  if (_send_cmd_to_amd(APP_STARTUP_SIGNAL) != 0)
+    _W("Failed to send startup signal");
+
+  return 0;
+}
+
+}  // namespace launchpad
diff --git a/src/lib/launchpad/step_prepare_execution.hh b/src/lib/launchpad/step_prepare_execution.hh
new file mode 100644 (file)
index 0000000..f95514b
--- /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 LIB_LAUNCHPAD_STEP_PREPARE_EXECUTION_HH_
+#define LIB_LAUNCHPAD_STEP_PREPARE_EXECUTION_HH_
+
+#include <functional>
+#include <vector>
+
+#include <app_info.hh>
+
+namespace launchpad {
+
+class StepPrepareExecution {
+ public:
+  StepPrepareExecution();
+  virtual ~StepPrepareExecution() = default;
+
+  int Prepare(AppInfo* app_info);
+
+ private:
+  int EnableExternalPackage(AppInfo* app_info);
+  int TrustAnchorLaunch(AppInfo* app_info);
+  int MountResourceDirectories(AppInfo* app_info);
+  int SecurityManagerPrepareApp(AppInfo* app_info);
+  int SetupStdio(AppInfo* app_info);
+  int BuxtonUpdateClientLabel(AppInfo* app_info);
+  int SetDumpable(AppInfo* app_info);
+  int SetProcessName(AppInfo* app_info);
+  int WaitTepMount(AppInfo* app_info);
+  int PrepareAppSocket(AppInfo* app_info);
+  int PrepareIdFile(AppInfo* app_info);
+  int SendStartupSignal(AppInfo* app_info);
+
+ private:
+  std::vector<std::function<int(AppInfo*)>> steps_;
+};
+
+}  // namespace launchpad
+
+#endif  // LIB_LAUNCHPAD_STEP_PREPARE_EXECUTION_HH_
diff --git a/src/lib/launchpad/thread_control.cc b/src/lib/launchpad/thread_control.cc
new file mode 100644 (file)
index 0000000..2f36b08
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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/thread_control.hh"
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+#include "launchpad/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+const int SIGRTINT = SIGRTMIN + 2;
+
+std::vector<pid_t> GetTasks() {
+  std::vector<pid_t> tasks;
+  std::filesystem::path task_path("/proc/self/task");
+  try {
+    for (auto& entry : std::filesystem::directory_iterator(task_path)) {
+      if (!std::isdigit(entry.path().filename().c_str()[0]))
+        continue;
+
+      tasks.push_back(std::stoi(entry.path().filename().string()));
+    }
+  } catch (const std::filesystem::filesystem_error& e) {
+    _E("Exception occurs. error: %s", e.what());
+  }
+
+  return tasks;
+}
+
+}  // namespace
+
+ThreadControl& ThreadControl::GetInst() {
+  static ThreadControl inst;
+  return inst;
+}
+
+ThreadControl::~ThreadControl() {
+  UnblockThreads();
+}
+
+int ThreadControl::BlockThreads() {
+  if (blocked_)
+    return 0;
+
+  if (!ChangeSigaction())
+    return -1;
+
+  InterruptThreads();
+  WaitThreads();
+  blocked_ = true;
+  return 0;
+}
+
+int ThreadControl::UnblockThreads() {
+  if (!blocked_)
+    return 0;
+
+  ContinueThreads();
+  WaitThreads();
+  RestoreSigaction();
+  blocked_ = false;
+  return 0;
+}
+
+bool ThreadControl::IsBlocked() const {
+  return blocked_;
+}
+
+int ThreadControl::GetCount() {
+  return GetTasks().size();
+}
+
+bool ThreadControl::ChangeSigaction() {
+  struct sigaction act;
+  memset(&act, '\0', sizeof(struct sigaction));
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  act.sa_handler = SignalHandler;
+
+  if (sigaction(SIGRTINT, &act, &old_action_) != 0) {
+    _E("sigaction() is failed. errno(%d)", errno);
+    return false;
+  }
+
+  return true;
+}
+
+void ThreadControl::InterruptThreads() {
+  pid_t pid = getpid();
+  auto tasks = GetTasks();
+  count_ = tasks.size() - 1;
+  _D("tasks count: %d", count_);
+  for (auto& tid : tasks) {
+    if (tid != pid) {
+      _D("Send signal to thread(%d)", tid);
+      if (tgkill(pid, tid, SIGRTINT) != 0) {
+        _E("tgkill() is failed. tid(%d), errno(%d)", tid, errno);
+        count_--;
+      }
+    }
+  }
+}
+
+void ThreadControl::ContinueThreads() {
+  std::unique_lock<std::mutex> lock(mutex_);
+  count_ = GetTasks().size() - 1;
+  _D("tasks count: %d", count_);
+  done_ = true;
+  cond_.notify_all();
+}
+
+void ThreadControl::WaitThreads() {
+  for (int i = 1000; count_ && i; --i)
+    usleep(2000);
+}
+
+void ThreadControl::RestoreSigaction() {
+  if (sigaction(SIGRTINT, &old_action_, nullptr) != 0)
+    _E("sigaction() is failed. errno(%d)", errno);
+}
+
+void ThreadControl::SignalHandler(int signo) {
+  _W("Block");
+  auto& inst = ThreadControl::GetInst();
+  std::unique_lock<std::mutex> lock(inst.mutex_);
+  inst.count_--;
+  inst.cond_.wait(lock, [&] { return inst.done_; });
+  inst.count_--;
+  _W("Unblock");
+}
+
+}  // namespace launchpad
diff --git a/src/lib/launchpad/thread_control.hh b/src/lib/launchpad/thread_control.hh
new file mode 100644 (file)
index 0000000..383adf2
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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_THREAD_CONTROL_HH_
+#define LIB_LAUNCHPAD_THREAD_CONTROL_HH_
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <mutex>
+#include <condition_variable>
+
+namespace launchpad {
+
+class ThreadControl {
+ public:
+  static ThreadControl& GetInst();
+
+  int BlockThreads();
+  int UnblockThreads();
+  bool IsBlocked() const;
+  int GetCount();
+
+ private:
+  ThreadControl() = default;
+  ~ThreadControl();
+
+  bool ChangeSigaction();
+  void InterruptThreads();
+  void ContinueThreads();
+  void WaitThreads();
+  void RestoreSigaction();
+  static void SignalHandler(int signo);
+
+ private:
+  struct sigaction old_action_ = { 0, };
+  std::mutex mutex_;
+  std::condition_variable cond_;
+  uint32_t count_ = 0;
+  uint32_t num_ = 0;
+  bool blocked_ = false;
+  bool done_ = false;
+};
+
+}  // namespace launchpad
+
+#endif  // LIB_LAUNCHPAD_THREAD_CONTROL_HH_