Mount gadget resource paths for NUIGadget
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 03:56:42 +0000 (12:56 +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 afb2e94e20e536547dd8c7e8a64689000a2aeaf5..c47d3cfb4b4d6cf47959ec689ea773d4d560dcf9 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 a2d29db175de48d2eb0555a4a44470de5f2c9135..88bbf6c96ed421bded602d0bd7eba9e5decb3775 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 88f2fbd6b5d4b82a0d73133e3795d4f3aa5ac55a..2b5945de3d3ef0c28ee7080d1b9bd6714a2a98b7 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 10b2b87edeb298d3a25b2d57a8c340be524dae59..513dc78b3659078441cf97546df3de67c5384c28 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 feaf15d8a9ae753c00c4d57c552c020f1a4ce0d3..814ff4b212959abf78227a62c17676b6fad8c484 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 e62b8c3ba125dbb9b08010135868034a137291eb..5d9b6044362f3202904641bdcb0a3d4cbf7cecae 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 f44da2cd865e386ec05f2bad001d0aa050d6def5..2208c82bac525876c209a2c6466a5baf837df695 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 472d556879d2789cd93865e2d1ae414bce38cb7d..7632d394d38de544b21ed40721f1a8028c3f685d 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 7f3f0783b32da76e6f5f5d8abcc7773f0dbdf38f..060c2c30efc16ebd205ebb8056d357c5dcac16fe 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 61e1a69212814ffcf9ea2e8a6fa218a8bc168a0c..b923aa4dd3004fc22f67ea166c1495b760523d05 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 e13ff466eea28956da003514cd4514d1e6a4bac1..b5861f61b708fa2e7d0aa81a81b5e4d6e8c6dc69 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 07713ac7c4f8478be63c9536d4c2f2ca02539369..fa490fab0f0b24214637653db38561225cb0a295 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 1c19ce00cc0c80ffcf97f4ceb90b4d1bf21d9ede..7da7fa30680d0a2416cc8ce15fef97fdca060049 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);