Mount gadget resource paths for NUIGadget 65/304565/10
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 19 Jan 2024 09:52:37 +0000 (18:52 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 23 Jan 2024 02:18:44 +0000 (11:18 +0900)
After this patch is applied, the launchpad tries to mount the gadget
resource package separately. And, the gadget packages will be mounted to
the bin directory of the application.
The 'loader-mount' process is added for mounting gadget packages.

Change-Id: Id6c4e6b5a3525eb5cc8687fbb28b6292e895ff3e
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
15 files changed:
src/launchpad-process-pool/app_executor.cc
src/launchpad-process-pool/hydra_loader_context.cc
src/launchpad-process-pool/hydra_loader_context.hh
src/launchpad-process-pool/loader_context.cc
src/launchpad-process-pool/loader_context.hh
src/launchpad-process-pool/loader_factory.cc
src/launchpad-process-pool/loader_factory.hh
src/launchpad-process-pool/loader_manager.cc
src/launchpad-process-pool/loader_manager.hh
src/launchpad-process-pool/loader_mount.cc [new file with mode: 0644]
src/launchpad-process-pool/loader_mount.hh [new file with mode: 0644]
src/lib/launchpad-common/aul_keys.hh
src/lib/launchpad-glib/util.cc
src/lib/launchpad-glib/util.hh
src/lib/launchpad/step_prepare_execution.cc

index afb2e94..c47d3cf 100644 (file)
@@ -200,6 +200,12 @@ int AppExecutor::StepEnableTrustAnchor() {
 }
 
 int AppExecutor::StepMountResDir() {
+  int ret = Util::MountGadgetDirectories(app_info_->GetBundle());
+  if (ret != 0) {
+    _E("Failed to mount gadget resources");
+    return ret;
+  }
+
   return Util::MountResourceDirectories(app_info_);
 }
 
index a2d29db..88bbf6c 100644 (file)
@@ -39,12 +39,14 @@ const int kSocketMaxBufferSize = 131071;
 
 HydraLoaderContext::Builder::operator LoaderContext*() {
   return new HydraLoaderContext(std::move(loader_info_), loader_id_,
-      caller_pid_, activated_);
+      caller_pid_, activated_, std::move(loader_mount_));
 }
 
-HydraLoaderContext::HydraLoaderContext(std::shared_ptr<LoaderInfo> loader_info,
-    int loader_id, pid_t caller_pid, bool activated)
-    : LoaderContext(std::move(loader_info), loader_id, caller_pid, activated) {
+HydraLoaderContext::HydraLoaderContext(
+    std::shared_ptr<LoaderInfo> loader_info, int loader_id, pid_t caller_pid,
+    bool activated, std::shared_ptr<LoaderMount> loader_mount)
+    : LoaderContext(std::move(loader_info), loader_id, caller_pid, activated,
+                    std::move(loader_mount)) {
   Listen();
 }
 
index 88f2fbd..2b5945d 100644 (file)
@@ -33,7 +33,8 @@ class HydraLoaderContext : public LoaderContext {
   };
 
   HydraLoaderContext(std::shared_ptr<LoaderInfo> loader_info, int loader_id,
-      pid_t caller_pid, bool activated);
+                     pid_t caller_pid, bool activated,
+                     std::shared_ptr<LoaderMount> loader_mount);
 
   void Listen() override;
   void Dispose() override;
index 10b2b87..513dc78 100644 (file)
@@ -124,20 +124,27 @@ LoaderContext::Builder& LoaderContext::Builder::SetActive() {
   return *this;
 }
 
+LoaderContext::Builder& LoaderContext::Builder::SetLoaderMount(
+    std::shared_ptr<LoaderMount> loader_mount) {
+  loader_mount_ = std::move(loader_mount);
+  return *this;
+}
+
 LoaderContext::Builder::operator LoaderContext*() {
   return new LoaderContext(std::move(loader_info_), loader_id_, caller_pid_,
-      activated_);
+                           activated_, std::move(loader_mount_));
 }
 
 LoaderContext::LoaderContext(std::shared_ptr<LoaderInfo> loader_info,
-    int loader_id, pid_t caller_pid, bool activated)
+                             int loader_id, pid_t caller_pid, bool activated,
+                             std::shared_ptr<LoaderMount> loader_mount)
     : loader_info_(std::move(loader_info)),
       loader_id_(loader_id),
       caller_pid_(caller_pid),
       activated_(activated),
-      cpu_checker_(
-          new CPUChecker(loader_info_->GetCpuThresholdMax(),
-              loader_info_->GetCpuThresholdMin())),
+      loader_mount_(std::move(loader_mount)),
+      cpu_checker_(new CPUChecker(loader_info_->GetCpuThresholdMax(),
+                                  loader_info_->GetCpuThresholdMin())),
       score_(kWinScore) {
   auto& executable_file = loader_info_->GetExe();
   if (executable_file != "null") {
@@ -238,6 +245,11 @@ pid_t LoaderContext::Prepare() {
 }
 
 pid_t LoaderContext::Deploy(const AppInfo* app_info) {
+  if (loader_mount_) {
+    if (loader_mount_->Mount(pid_, app_info) != 0)
+      _E("Failed to attach resources to loader process");
+  }
+
   Util::DeleteSocketPath(pid_, getuid());
   tizen_base::Parcel parcel;
   parcel.WriteParcelable(*app_info);
index feaf15d..814ff4b 100644 (file)
@@ -32,6 +32,7 @@
 #include "launchpad-process-pool/cpu_checker.hh"
 #include "launchpad-process-pool/loader_info.hh"
 #include "launchpad-process-pool/launcher_info.hh"
+#include "launchpad-process-pool/loader_mount.hh"
 
 namespace launchpad {
 
@@ -46,6 +47,7 @@ class LoaderContext : public std::enable_shared_from_this<LoaderContext>,
     Builder& SetLoaderId(int loader_id);
     Builder& SetCallerPid(pid_t caller_pid);
     Builder& SetActive();
+    Builder& SetLoaderMount(std::shared_ptr<LoaderMount> loader_mount);
 
     virtual operator LoaderContext*();
 
@@ -54,6 +56,7 @@ class LoaderContext : public std::enable_shared_from_this<LoaderContext>,
     int loader_id_ = 0;
     pid_t caller_pid_ = getpid();
     bool activated_ = true;
+    std::shared_ptr<LoaderMount> loader_mount_;
   };
 
   class IEvent {
@@ -65,7 +68,8 @@ class LoaderContext : public std::enable_shared_from_this<LoaderContext>,
   };
 
   LoaderContext(std::shared_ptr<LoaderInfo> loader_info, int loader_id,
-      pid_t caller_pid, bool activated);
+                pid_t caller_pid, bool activated,
+                std::shared_ptr<LoaderMount> loader_mount);
   virtual ~LoaderContext();
 
   virtual void Listen();
@@ -136,6 +140,7 @@ class LoaderContext : public std::enable_shared_from_this<LoaderContext>,
   int loader_id_;
   pid_t caller_pid_;
   bool activated_;
+  std::shared_ptr<LoaderMount> loader_mount_;
   std::unique_ptr<CPUChecker> cpu_checker_;
   unsigned int score_;
   std::string loader_extra_;
index e62b8c3..5d9b604 100644 (file)
@@ -75,7 +75,7 @@ LoaderFactory& LoaderFactory::GetInst() {
 }
 
 std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
-    LoaderInfoPtr info) {
+    LoaderInfoPtr info, std::shared_ptr<LoaderMount> loader_mount) {
   auto app_types = GetAppTypeString(info);
   int loader_id = static_cast<int>((info->GetExe() == "null") ?
       PadLoaderId::Direct : PadLoaderId::Static);
@@ -85,12 +85,14 @@ std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
       context = HydraLoaderContext::Builder()
         .SetLoaderInfo(std::move(info))
         .SetLoaderId(loader_id)
-        .SetActive();
+        .SetActive()
+        .SetLoaderMount(std::move(loader_mount));
     } else {
       context = LoaderContext::Builder()
         .SetLoaderInfo(std::move(info))
         .SetLoaderId(loader_id)
-        .SetActive();
+        .SetActive()
+        .SetLoaderMount(std::move(loader_mount));
     }
   } catch (const Exception& e) {
     _E("Exception occurs. error(%s)", e.what());
@@ -109,7 +111,7 @@ std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
 }
 
 std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
-    tizen_base::Bundle b) {
+    tizen_base::Bundle b, std::shared_ptr<LoaderMount> loader_mount) {
   auto caller_pid = b.GetString(kAulCallerPid);
   if (caller_pid.empty())
     return nullptr;
@@ -126,7 +128,8 @@ std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
         .SetLoaderInfo(std::move(loader_info))
         .SetLoaderId(loader_id)
         .SetCallerPid(std::stoi(caller_pid))
-        .SetActive();
+        .SetActive()
+        .SetLoaderMount(std::move(loader_mount));
     if (context == nullptr)
         return nullptr;
   } catch (const Exception& e) {
@@ -138,7 +141,8 @@ std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
 }
 
 std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
-    LoaderInfoPtr info, pid_t caller_pid) {
+    LoaderInfoPtr info, pid_t caller_pid,
+    std::shared_ptr<LoaderMount> loader_mount) {
   int loader_id = MakeDynamicLoaderId();
   LoaderContext* context;
   try {
@@ -146,7 +150,8 @@ std::shared_ptr<LoaderContext> LoaderFactory::CreateLoaderContext(
         .SetLoaderInfo(std::move(info))
         .SetLoaderId(loader_id)
         .SetCallerPid(caller_pid)
-        .SetActive();
+        .SetActive()
+        .SetLoaderMount(std::move(loader_mount));
     if (context == nullptr)
       return nullptr;
   } catch (const Exception& e) {
index f44da2c..2208c82 100644 (file)
@@ -36,10 +36,13 @@ class LoaderFactory {
 
   static LoaderFactory& GetInst();
 
-  std::shared_ptr<LoaderContext> CreateLoaderContext(LoaderInfoPtr info);
-  std::shared_ptr<LoaderContext> CreateLoaderContext(tizen_base::Bundle b);
-  std::shared_ptr<LoaderContext> CreateLoaderContext(LoaderInfoPtr info,
-      pid_t caller_pid);
+  std::shared_ptr<LoaderContext> CreateLoaderContext(
+      LoaderInfoPtr info, std::shared_ptr<LoaderMount> loader_mount);
+  std::shared_ptr<LoaderContext> CreateLoaderContext(
+      tizen_base::Bundle b, std::shared_ptr<LoaderMount> loader_mount);
+  std::shared_ptr<LoaderContext> CreateLoaderContext(
+      LoaderInfoPtr info, pid_t caller_pid,
+      std::shared_ptr<LoaderMount> loader_mount);
 
  private:
   LoaderFactory() = default;
index 472d556..7632d39 100644 (file)
@@ -43,6 +43,7 @@ void LoaderManager::Dispose() {
   if (disposed_)
     return;
 
+  loader_mount_.reset();
   hwacc_config_.reset();
   app_defined_loader_info_manager_.reset();
   loader_info_manager_.reset();
@@ -65,6 +66,11 @@ void LoaderManager::Init() {
     app_defined_loader_info_manager_.reset(new AppDefinedLoaderInfoManager());
     app_defined_loader_info_manager_->SetEventListener(this);
     hwacc_config_.reset(new HWAccelerationConfig());
+
+    if (!label_monitor.IsDisposed()) {
+      setenv("LOADER_MOUNT", "1", 1);
+      loader_mount_.reset(new LoaderMount());
+    }
   } catch (const Exception& e) {
     _E("Exception occurs. error: %s", e.what());
     return;
@@ -73,6 +79,12 @@ void LoaderManager::Init() {
   disposed_ = false;
 }
 
+void LoaderManager::PrepareApp(const std::shared_ptr<LoaderContext>& context,
+                               const AppInfo* app_info) {
+  pid_t pid = context->GetPid();
+  loader_mount_->Mount(pid, app_info);
+}
+
 void LoaderManager::SetEventListener(LoaderManager::IEvent* event_listener) {
   event_listener_ = event_listener;
 }
@@ -94,6 +106,7 @@ void LoaderManager::HandleSigchld(pid_t pid) {
 
   RemoveLoaderContextsByCallerPid(pid);
   LoaderExecutor::GetInst().HandleSigchld(pid);
+  if (loader_mount_) loader_mount_->HandleSigchld(pid);
 }
 
 void LoaderManager::AddDefaultLoaderContexts() {
@@ -101,7 +114,8 @@ void LoaderManager::AddDefaultLoaderContexts() {
   loader_info_manager_->Load();
 
   for (auto& info : loader_info_manager_->GetLoaderInfoList()) {
-    auto context = LoaderFactory::GetInst().CreateLoaderContext(info);
+    auto context =
+        LoaderFactory::GetInst().CreateLoaderContext(info, loader_mount_);
     if (context != nullptr) {
       context->SetEventListener(this);
       loader_contexts_.push_back(std::move(context));
@@ -148,7 +162,8 @@ std::shared_ptr<LoaderContext> LoaderManager::PrepareAppDefinedLoaderContext(
 
   auto context = FindLoaderContextFromName(name);
   if (context == nullptr) {
-    context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid);
+    context = LoaderFactory::GetInst().CreateLoaderContext(info, caller_pid,
+                                                           loader_mount_);
     if (context == nullptr) {
       _E("Failed to create loader context. loader_name: %s",
           name.c_str());
@@ -166,7 +181,8 @@ std::shared_ptr<LoaderContext> LoaderManager::PrepareAppDefinedLoaderContext(
 
 std::shared_ptr<LoaderContext> LoaderManager::AddLoaderContext(
     tizen_base::Bundle b) {
-  auto context = LoaderFactory::GetInst().CreateLoaderContext(std::move(b));
+  auto context =
+      LoaderFactory::GetInst().CreateLoaderContext(std::move(b), loader_mount_);
   if (context == nullptr)
     return nullptr;
 
index 7f3f078..060c2c3 100644 (file)
@@ -26,6 +26,7 @@
 #include <string_view>
 #include <vector>
 
+#include <app_info.hh>
 #include <hw_acceleration_config.hh>
 
 #include "launchpad-process-pool/app_defined_loader_info_manager.hh"
@@ -33,6 +34,7 @@
 #include "launchpad-process-pool/hydra_loader_context.hh"
 #include "launchpad-process-pool/loader_context.hh"
 #include "launchpad-process-pool/loader_info.hh"
+#include "launchpad-process-pool/loader_mount.hh"
 #include "launchpad-process-pool/memory_monitor.hh"
 #include "launchpad-process-pool/sequencer.hh"
 
@@ -59,6 +61,8 @@ class LoaderManager : public AppDefinedLoaderInfoManager::IEvent,
   static LoaderManager& GetInst();
   void Dispose();
 
+  void PrepareApp(const std::shared_ptr<LoaderContext>& context,
+                  const AppInfo* app_info);
   void SetEventListener(IEvent* event_listener);
   void HandleSigchld(pid_t pid);
   void AddDefaultLoaderContexts();
@@ -117,6 +121,7 @@ class LoaderManager : public AppDefinedLoaderInfoManager::IEvent,
   std::unique_ptr<AppDefinedLoaderInfoManager> app_defined_loader_info_manager_;
   std::vector<std::shared_ptr<LoaderContext>> loader_contexts_;
   std::unique_ptr<HWAccelerationConfig> hwacc_config_;
+  std::shared_ptr<LoaderMount> loader_mount_;
 };
 
 }  // namespace launchpad
diff --git a/src/launchpad-process-pool/loader_mount.cc b/src/launchpad-process-pool/loader_mount.cc
new file mode 100644 (file)
index 0000000..db264e8
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2024 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/loader_mount.hh"
+
+#include <bundle_cpp.h>
+#include <bundle_internal.h>
+#include <dlog-redirect-stdout.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/limits.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <aul_keys.hh>
+#include <exception.hh>
+#include <parcelable.hh>
+#include <util.hh>
+
+#include "launchpad-process-pool/launchpad_args.hh"
+#include "launchpad-process-pool/log_private.hh"
+
+namespace fs = std::filesystem;
+namespace {
+
+bool IsExceptable(const std::string& path) {
+  static char buf[PATH_MAX];
+  ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
+  if (len < 0) {
+    _E("readlink() is failed. errno: %d", errno);
+    return false;
+  }
+
+  buf[len] = '\0';
+  if (strstr(buf, "log") != nullptr ||
+      strstr(buf, "trace") != nullptr ||
+      strstr(buf, "dev") != nullptr)
+    return true;
+
+  return false;
+}
+
+std::vector<int> GetExceptableFds() {
+  std::vector<int> fds;
+  try {
+    fs::path proc_path("/proc/self/fd");
+    for (const auto& entry : fs::directory_iterator(proc_path)) {
+      if (!isdigit(entry.path().filename().string()[0]))
+        continue;
+
+      int fd = std::stoi(entry.path().filename().string());
+      if (dlog_is_log_fd(fd) || IsExceptable(entry.path().string()))
+        fds.push_back(fd);
+    }
+  } catch (const fs::filesystem_error& e) {
+    _E("Exception occurs. error(%s)", e.what());
+  }
+
+  return fds;
+}
+
+int ChangeMountNamespace(pid_t pid) {
+  std::string mnt_path = "/proc/" + std::to_string(pid) + "/ns/mnt";
+  int fd = open(mnt_path.c_str(), O_RDONLY);
+  if (fd < 0) {
+    _E("open() is failed. path(%s), errno(%d)", mnt_path.c_str(), errno);
+    return -1;
+  }
+
+  int ret = ::setns(fd, 0);
+  close(fd);
+  if (ret != 0) {
+    _E("setns() is failed. path(%s), errno(%d)", mnt_path.c_str(), errno);
+    return -1;
+  }
+
+  _D("setns() is successful. pid(%d)", pid);
+  return 0;
+}
+
+class Request : public tizen_base::Parcelable {
+ public:
+  explicit Request(tizen_base::Parcel* parcel) { ReadFromParcel(parcel); }
+
+  Request(pid_t pid, tizen_base::Bundle b) : pid_(pid), b_(std::move(b)) {}
+
+  pid_t GetPid() const { return pid_; }
+
+  const tizen_base::Bundle& GetBundle() const { return b_; }
+
+  void WriteToParcel(tizen_base::Parcel* parcel) const override {
+    parcel->WriteInt32(pid_);
+    bundle_raw* raw = nullptr;
+    int len = 0;
+    bundle_encode(b_.GetHandle(), &raw, &len);
+    parcel->WriteInt32(len);
+    parcel->Write(reinterpret_cast<unsigned char*>(raw), len);
+    bundle_free_encoded_rawdata(&raw);
+  }
+
+  void ReadFromParcel(tizen_base::Parcel* parcel) override {
+    parcel->ReadInt32(&pid_);
+    int len = 0;
+    parcel->ReadInt32(&len);
+    if (len > 0) {
+      std::vector<uint8_t> data(len);
+      parcel->Read(data.data(), data.size());
+      b_ = tizen_base::Bundle(
+          bundle_decode(reinterpret_cast<bundle_raw*>(data.data()), len), false,
+          true);
+    }
+  }
+
+ private:
+  pid_t pid_;
+  tizen_base::Bundle b_;
+};
+
+class Reply : public tizen_base::Parcelable {
+ public:
+  explicit Reply(tizen_base::Parcel* parcel) { ReadFromParcel(parcel); }
+
+  explicit Reply(int result) : result_(result) {}
+
+  int GetResult() const { return result_; }
+
+  void WriteToParcel(tizen_base::Parcel* parcel) const override {
+    parcel->WriteInt32(result_);
+  }
+
+  void ReadFromParcel(tizen_base::Parcel* parcel) override {
+    parcel->ReadInt32(&result_);
+  }
+
+ private:
+  int result_ = -1;
+};
+
+}  // namespace
+
+namespace launchpad {
+
+LoaderMount::LoaderMount() : Executor(this), launchpad_ppid_(getppid()) {
+  Prepare();
+}
+
+LoaderMount::~LoaderMount() { Dispose(); }
+
+void LoaderMount::Prepare() {
+  if (pid_ > 0) return;
+
+  int pipe_fd[2];
+  if (CreatePipe(&pipe_fd) != 0) return;
+
+  read_socket_.reset(new Socket(pipe_fd[0]));
+  int write_fd = pipe_fd[1];
+
+  if (CreatePipe(&pipe_fd) != 0) return;
+
+  int read_fd = pipe_fd[0];
+  write_socket_.reset(new Socket(pipe_fd[1]));
+
+  _W("read_socket=%d, write_socket=%d",
+     read_socket_->GetFd(), write_socket_->GetFd());
+  pid_ = Executor::Execute();
+  if (pid_ == -1) {
+    _E("Failed to fork process. errno(%d)", errno);
+    close(read_fd);
+    close(write_fd);
+    return;
+  }
+
+  read_socket_.reset(new Socket(read_fd));
+  write_socket_.reset(new Socket(write_fd));
+}
+
+void LoaderMount::Dispose() {
+  read_socket_.reset();
+  write_socket_.reset();
+  if (pid_ > 0) {
+    if (kill(pid_, SIGKILL) == -1)
+      _E("Failed to send kill signal. pid(%d), errno(%d)", pid_, errno);
+
+    pid_ = -1;
+  }
+}
+
+void LoaderMount::HandleSigchld(pid_t pid) {
+  if (pid_ != pid) return;
+
+  pid_ = -1;
+  Dispose();
+  Prepare();
+}
+
+int LoaderMount::Mount(pid_t pid, const AppInfo* app_info) {
+  auto& b = app_info->GetBundle();
+  if (b.GetType(kAulMountGadgetPaths) == BUNDLE_TYPE_NONE) return 0;
+
+  tizen_base::Parcel parcel;
+  Request request(pid, b);
+  request.WriteToParcel(&parcel);
+
+  _W("Send mount request");
+  int ret = Write(parcel);
+  if (ret != 0) return ret;
+
+  parcel.Clear();
+  ret = Read(&parcel);
+  if (ret!= 0) return ret;
+
+  _W("receive result");
+  Reply reply(&parcel);
+  return reply.GetResult();
+}
+
+void LoaderMount::OnExecution() {
+  _D("Mount Manager");
+  char** args = LaunchpadArgs::GetInst().GetArgs();
+  size_t length = strlen(args[0]);
+  memset(args[0], '\0', length);
+  snprintf(args[0], length, "/usr/bin/loader-mount");
+
+  std::vector<int> except_fds = GetExceptableFds();
+  except_fds.push_back(read_socket_->GetFd());
+  except_fds.push_back(write_socket_->GetFd());
+  Util::CloseAllFds(except_fds);
+  int ret = ProcessRequests();
+  exit(ret);
+}
+
+
+int LoaderMount::CreatePipe(int (*pipe_fd)[2]) {
+  *pipe_fd[0] = -1;
+  *pipe_fd[2] = -1;
+
+  if (pipe(*pipe_fd) == -1) {
+    _E("pipe() is failed. errno(%d)", errno);
+    return -1;
+  }
+
+  if (fcntl(*pipe_fd[0], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
+    _E("Failed to set pipe size. errno(%d)", errno);
+
+  if (fcntl(*pipe_fd[1], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
+    _E("Failed to set pipe size. errno(%d)", errno);
+
+  return 0;
+}
+
+int LoaderMount::Write(const tizen_base::Parcel& parcel) {
+  size_t data_size = parcel.GetDataSize();
+  int ret =
+      write_socket_->Write(static_cast<void*>(&data_size), sizeof(data_size));
+  if (ret != 0) {
+    _E("Write() is failed. error(%d)", ret);
+    return -1;
+  }
+
+  return write_socket_->Write(parcel.GetData(), parcel.GetDataSize());
+}
+
+int LoaderMount::Read(tizen_base::Parcel* parcel) {
+  size_t data_size = 0;
+  int ret =
+      read_socket_->Read(static_cast<void*>(&data_size), sizeof(data_size));
+  if (ret != 0) {
+    _E("Read() is failed. error(%d)", ret);
+    return -1;
+  }
+
+  std::vector<uint8_t> data(data_size);
+  ret = read_socket_->Read(data.data(), data.size());
+  if (ret != 0) {
+    _E("Read() is failed. error(%d)", ret);
+    return -1;
+  }
+
+  parcel->Write(data.data(), data.size());
+  return 0;
+}
+
+int LoaderMount::ProcessRequests() {
+  tizen_base::Parcel parcel;
+  while (true) {
+    parcel.Clear();
+    int ret = Read(&parcel);
+    if (ret != 0) continue;
+
+    _W("Request received");
+    Request request(&parcel);
+    ret = ChangeMountNamespace(request.GetPid());
+    if (ret == 0) {
+      ret = Util::MountGadgetDirectories(request.GetBundle());
+      ChangeMountNamespace(launchpad_ppid_);
+    }
+
+    Reply reply(ret);
+    parcel.Clear();
+    reply.WriteToParcel(&parcel);
+    Write(parcel);
+  }
+
+  return 0;
+}
+
+}  // namespace launchpad
diff --git a/src/launchpad-process-pool/loader_mount.hh b/src/launchpad-process-pool/loader_mount.hh
new file mode 100644 (file)
index 0000000..6bc2274
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 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_LOADER_MOUNT_HH_
+#define LAUNCHPAD_PROCESS_POOL_LOADER_MOUNT_HH_
+
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <app_info.hh>
+#include <parcel.hh>
+#include <socket.hh>
+
+#include "launchpad-process-pool/executor.hh"
+
+namespace launchpad {
+
+class LoaderMount : public Executor::Delegator, public Executor {
+ public:
+  LoaderMount();
+  virtual ~LoaderMount();
+
+  void Prepare();
+  void Dispose();
+  void HandleSigchld(pid_t pid);
+
+  int Mount(pid_t pid, const AppInfo* app_info);
+
+ private:
+  void OnExecution() override;
+  int CreatePipe(int (*pipe_fd)[2]);
+  int Write(const tizen_base::Parcel& parcel);
+  int Read(tizen_base::Parcel* parcel);
+  int ProcessRequests();
+
+ private:
+  pid_t launchpad_ppid_ = -1;
+  pid_t pid_ = -1;
+  std::unique_ptr<Socket> read_socket_;
+  std::unique_ptr<Socket> write_socket_;
+};
+
+}  // namespace launchpad
+
+#endif  // LAUNCHPAD_PROCESS_POOL_LOADER_MOUNT_HH_
index 61e1a69..b923aa4 100644 (file)
@@ -54,6 +54,8 @@ constexpr const char kAulTaskManage[] = "__AUL_TASKMANAGE__";
 constexpr const char kAulTepPath[] = "__AUL_TEP_PATH__";
 constexpr const char kAulWaylandDisplay[] = "__AUL_WAYLAND_DISPLAY__";
 constexpr const char kAulWaylandWorkingDir[] = "__AUL_WAYLAND_WORKING_DIR__";
+constexpr const char kAulMountGadgetPaths[] = "__AUL_MOUNT_GADGET_PATHS__";
+constexpr const char kAulMountGadgetPkgIds[] = "__AUL_MOUNT_GADGET_PKGIDS__";
 
 }  // namespace launchpad
 
index e13ff46..b5861f6 100644 (file)
@@ -95,6 +95,20 @@ void SetRegionFormatEnvironments() {
   setenv("LC_IDENTIFICATION", region, 1);
 }
 
+void SetGadgetPkgIdsEnvironments(const tizen_base::Bundle& b) {
+  auto gadget_pkgids = b.GetStringArray(kAulMountGadgetPkgIds);
+  if (gadget_pkgids.empty()) return;
+
+  std::string pkgids;
+  for (auto& pkgid : gadget_pkgids) {
+    if (!pkgids.empty()) pkgids += ":";
+
+    pkgids += pkgid;
+  }
+
+  setenv("GADGET_PKGIDS", pkgids.c_str(), 1);
+}
+
 #ifdef TIZEN_FEATURE_SET_PERSONALITY_32
 static void SetExecutionDomain() {
   int ret = personality(PER_LINUX32);
@@ -241,7 +255,7 @@ class TepMountChecker : public DBus {
   std::vector<std::string> paths_;
 };
 
-void MountDirectories(const std::vector<std::string>& srcs,
+int MountDirectories(const std::vector<std::string>& srcs,
     const std::string& dest) {
   std::string opt = "lowerdir=" + dest;
   for (auto& src : srcs)
@@ -251,6 +265,8 @@ void MountDirectories(const std::vector<std::string>& srcs,
   int ret = mount(nullptr, dest.c_str(), "overlay", MS_RDONLY, opt.c_str());
   if (ret != 0)
     _E("mount() is failed. dest(%s), errno(%d)", dest.c_str(), errno);
+
+  return ret;
 }
 
 class ExternalPackage : public DBus {
@@ -407,6 +423,7 @@ void Util::SetEnvironments(const AppInfo* app_info) {
 
   setenv("GCOV_PREFIX", "/tmp", 1);
   setenv("DALI_DISABLE_PARTIAL_UPDATE", "0", 1);
+  SetGadgetPkgIdsEnvironments(b);
 }
 
 void Util::DeleteSocketPath(pid_t pid, uid_t uid) {
@@ -467,6 +484,16 @@ int Util::MountResourceDirectories(const AppInfo* app_info) {
   return 0;
 }
 
+int Util::MountGadgetDirectories(const tizen_base::Bundle& b) {
+  auto gadget_paths = b.GetStringArray(kAulMountGadgetPaths);
+  if (!gadget_paths.empty()) {
+    auto root_path = b.GetString(kAulRootPath);
+    return MountDirectories(gadget_paths, root_path + "/bin");
+  }
+
+  return 0;
+}
+
 int Util::WaitTepMount(const AppInfo* app_info) {
   if (app_info->GetBundle().GetType(kAulTepPath) == BUNDLE_TYPE_NONE)
     return 0;
index 07713ac..fa490fa 100644 (file)
@@ -41,6 +41,7 @@ class EXPORT_API Util {
   static void DeleteSocketPath(pid_t pid, uid_t uid);
   static int EnableExternalPackage(const AppInfo* app_info);
   static int MountResourceDirectories(const AppInfo* app_info);
+  [[nodiscard]] static int MountGadgetDirectories(const tizen_base::Bundle& b);
   static int WaitTepMount(const AppInfo* app_info);
   static std::string GetLibDirectory(const std::string& app_path);
   static void CloseAllFds(const std::vector<int>& except_fds = {});
index 1c19ce0..7da7fa3 100644 (file)
@@ -98,6 +98,13 @@ int StepPrepareExecution::TrustAnchorLaunch(AppInfo* app_info) {
 }
 
 int StepPrepareExecution::MountResourceDirectories(AppInfo* app_info) {
+  if (getenv("LOADER_MOUNT") == nullptr) {
+    if (Util::MountGadgetDirectories(app_info->GetBundle()) != 0) {
+      _E("Failed to mount gadget resources");
+      return -1;
+    }
+  }
+
   int ret = Util::MountResourceDirectories(app_info);
   if (ret < 0) {
     _E("Failed to mount resource direstories. error: %d", ret);