Support Process pool feature 45/291545/14
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 18 Apr 2023 06:39:19 +0000 (06:39 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Wed, 19 Apr 2023 04:39:33 +0000 (04:39 +0000)
Launchpad is introducing a process pool. The process pool class creates
child processes, which are used to execute application launch requests or
to create loader processes. This feature is used to improve performance.
The PSS memory usage of candidate processes is not high, typically ranging
from 400 to 500.

Change-Id: I0142e7c15d12295741c46fa5e203caa664dea0d9
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
16 files changed:
CMakeLists.txt
packaging/launchpad.spec
src/launchpad-process-pool/app_executor.cc
src/launchpad-process-pool/app_executor.hh
src/launchpad-process-pool/loader_executor.cc
src/launchpad-process-pool/loader_executor.hh
src/launchpad-process-pool/process_pool.cc [new file with mode: 0644]
src/launchpad-process-pool/process_pool.hh [new file with mode: 0644]
src/launchpad-process-pool/worker.cc
src/launchpad-process-pool/worker.hh
src/lib/launchpad-common/CMakeLists.txt
src/lib/launchpad-common/app_packet.cc [new file with mode: 0644]
src/lib/launchpad-common/app_packet.hh [new file with mode: 0644]
src/lib/launchpad-common/pkgconfig/liblaunchpad-common.pc.in
src/lib/launchpad-common/procfs.cc
src/lib/launchpad-common/procfs.hh

index 2814f5b..ac8c783 100644 (file)
@@ -72,6 +72,7 @@ PKG_CHECK_MODULES(TANCHOR_DEPS REQUIRED tanchor)
 PKG_CHECK_MODULES(TIZEN_SHARED_QUEUE_DEPS REQUIRED tizen-shared-queue)
 PKG_CHECK_MODULES(TTRACE_DEPS REQUIRED ttrace)
 PKG_CHECK_MODULES(VCONF_DEPS REQUIRED vconf)
+PKG_CHECK_MODULES(PARCEL_DEPS REQUIRED parcel)
 
 ENABLE_TESTING()
 ADD_TEST(NAME ${TARGET_LAUNCHPAD_PROCESS_POOL_UNITTEST}
index 4dc7d5f..bb01a7d 100644 (file)
@@ -35,6 +35,7 @@ BuildRequires:  pkgconfig(tanchor)
 BuildRequires:  pkgconfig(tizen-shared-queue)
 BuildRequires:  pkgconfig(ttrace)
 BuildRequires:  pkgconfig(vconf)
+BuildRequires:  pkgconfig(parcel)
 
 Requires(post): /sbin/ldconfig
 Requires(post): /usr/bin/systemctl
index a5d6f95..a4155aa 100644 (file)
@@ -25,6 +25,7 @@
 #include <unistd.h>
 
 #include <filesystem>
+#include <utility>
 
 #include <aul_keys.hh>
 #include <plugin.hh>
 
 namespace launchpad {
 namespace fs = std::filesystem;
+namespace {
 
-AppExecutor::AppExecutor() : Executor(this) {
+std::shared_ptr<AppPacket> CreateAppPacketFromAppInfo(const AppInfo* app_info) {
+    auto raw = const_cast<tizen_base::Bundle&>(app_info->GetBundle()).ToRaw();
+    std::vector<uint8_t> data(raw.first.get(), raw.first.get() + raw.second);
+    return std::shared_ptr<AppPacket>(new AppPacket(0, 0, std::move(data)));
+}
+
+std::shared_ptr<AppInfo> CreateAppInfoFromAppPacket(
+    const AppPacket* app_packet) {
+  auto& data = app_packet->GetData();
+  std::string raw(data.begin(), data.end());
+  tizen_base::Bundle b(raw);
+  return std::shared_ptr<AppInfo>(AppInfo::Create(std::move(b)));
+}
+
+}  // namespace
+
+AppExecutor::AppExecutor()
+    : Executor(this), process_pool_(new ProcessPool(2, this)) {
   LauncherInfoInflator inflator;
   launcher_infos_ = inflator.Inflate("/usr/share/aul");
 
@@ -75,6 +94,11 @@ AppExecutor::AppExecutor() : Executor(this) {
 }
 
 pid_t AppExecutor::Execute(const AppInfo* app_info) {
+  if (process_pool_->IsPrepared()) {
+    auto app_packet = CreateAppPacketFromAppInfo(app_info);
+    return process_pool_->Execute(std::move(app_packet));
+  }
+
   app_info_ = app_info;
   return Executor::Execute();
 }
@@ -122,6 +146,13 @@ void AppExecutor::OnExecution() {
   }
 }
 
+void AppExecutor::OnRequestReceived(std::shared_ptr<AppPacket> app_packet) {
+  _W("Request received");
+  auto app_info = CreateAppInfoFromAppPacket(app_packet.get());
+  app_info_ = app_info.get();
+  OnExecution();
+}
+
 int AppExecutor::Prepare() {
   for (auto& func : prepare_funcs_) {
     if (func() != 0)
index 78bebc9..2977219 100644 (file)
 #include <functional>
 #include <string>
 #include <vector>
+#include <memory>
 
 #include <app_info.hh>
 
 #include "launchpad-process-pool/executor.hh"
 #include "launchpad-process-pool/launcher_info.hh"
+#include "launchpad-process-pool/process_pool.hh"
 
 namespace launchpad {
 
 class AppExecutor : public Executor::Delegator,
-                    public Executor {
+                    public Executor,
+                    public ProcessPool::IEvent {
  public:
   AppExecutor();
 
@@ -39,6 +42,7 @@ class AppExecutor : public Executor::Delegator,
 
  private:
   void OnExecution() override;
+  void OnRequestReceived(std::shared_ptr<AppPacket> app_packet) override;
 
   int Prepare();
   int StepCreateNewSession();
@@ -64,6 +68,7 @@ class AppExecutor : public Executor::Delegator,
  private:
   using PrepareFunc = std::function<int()>;
 
+  std::unique_ptr<ProcessPool> process_pool_;
   std::vector<LauncherInfoPtr> launcher_infos_;
   std::vector<PrepareFunc> prepare_funcs_;
   const AppInfo* app_info_ = nullptr;
index 7f66558..601a61d 100644 (file)
 
 #include <utility>
 
+#include <parcel.hh>
+
 #include "launchpad-process-pool/log_private.hh"
 #include "launchpad-process-pool/signal_manager.hh"
 #include "lib/common/inc/launchpad_common.h"
 #include "lib/common/inc/launchpad_types.h"
 
 namespace launchpad {
+namespace {
+
+std::shared_ptr<AppPacket> CreateAppPacketFromArgs(
+    const std::vector<std::string>& args) {
+  tizen_base::Bundle b;
+  b.Add("LOADER_ARGS", args);
+  auto raw = b.ToRaw();
+  std::vector<uint8_t> data(raw.first.get(), raw.first.get() + raw.second);
+  return std::shared_ptr<AppPacket>(new AppPacket(0, 0, std::move(data)));
+}
 
-LoaderExecutor::LoaderExecutor() : Executor(this) {}
+std::vector<std::string> CreateArgsFromAppPacket(const AppPacket* app_packet) {
+  auto& data = app_packet->GetData();
+  std::string raw(data.begin(), data.end());
+  tizen_base::Bundle b(raw);
+  return b.GetStringArray("LOADER_ARGS");
+}
+
+}  // namespace
+
+LoaderExecutor::LoaderExecutor()
+    : Executor(this), process_pool_(new ProcessPool(2, this)) {}
 
 LoaderExecutor& LoaderExecutor::GetInst() {
   static LoaderExecutor inst;
@@ -38,22 +60,20 @@ LoaderExecutor& LoaderExecutor::GetInst() {
 
 pid_t LoaderExecutor::Execute(const LoaderContext* loader_context,
     int priority) {
-  loader_context_ = loader_context;
+  loader_argv_ = CreateLoaderArgv(loader_context);
+  if (process_pool_->IsPrepared()) {
+    auto app_packet = CreateAppPacketFromArgs(loader_argv_);
+    return process_pool_->Execute(std::move(app_packet));
+  }
+
   return Executor::Execute(priority);
 }
 
 void LoaderExecutor::OnExecution() {
-  std::vector<std::string> argv = CreateLoaderArgv();
-  char** loader_argv = static_cast<char**>(
-      calloc(argv.size() + 1, sizeof(char*)));
-  if (loader_argv == nullptr) {
-    _E("Out of memory");
-    exit(EXIT_FAILURE);
-  }
-
-  int loader_argc = argv.size();
+  std::vector<char*> loader_argv(loader_argv_.size() + 1);
+  int loader_argc = loader_argv_.size();
   for (int i = 0; i < loader_argc; ++i) {
-    loader_argv[i] = const_cast<char*>(argv[i].c_str());
+    loader_argv[i] = const_cast<char*>(loader_argv_[i].c_str());
     if ((i + 1) != loader_argc)
       SECURE_LOGD("loader argument %d : %s##", i, loader_argv[i]);
   }
@@ -62,24 +82,31 @@ void LoaderExecutor::OnExecution() {
   _close_all_fds();
   _setup_stdio(basename(loader_argv[LOADER_ARG_PATH]));
 
-  if (execv(loader_argv[LOADER_ARG_PATH], loader_argv) < 0) {
+  if (execv(loader_argv[LOADER_ARG_PATH], loader_argv.data()) < 0) {
     char err_buf[1024];
     fprintf(stderr, "Failed to execute a file. path: %s, errno: %d:%s\n",
-            loader_argv[LOADER_ARG_PATH], errno,
-            strerror_r(errno, err_buf, sizeof(err_buf)));
+        loader_argv[LOADER_ARG_PATH], errno,
+        strerror_r(errno, err_buf, sizeof(err_buf)));
     exit(EXIT_FAILURE);
   }
 }
 
-std::vector<std::string> LoaderExecutor::CreateLoaderArgv() {
+void LoaderExecutor::OnRequestReceived(std::shared_ptr<AppPacket> app_packet) {
+  _W("Request received");
+  loader_argv_ = CreateArgsFromAppPacket(app_packet.get());
+  OnExecution();
+}
+
+std::vector<std::string> LoaderExecutor::CreateLoaderArgv(
+    const LoaderContext* loader_context) {
   std::string dummy(LOADER_ARG_LEN - 1, ' ');
   std::vector<std::string> argv(LOADER_ARG_DUMMY + 1);
   argv[LOADER_ARG_DUMMY] = std::move(dummy);
-  argv[LOADER_ARG_PATH] = loader_context_->GetLoaderPath();
-  argv[LOADER_ARG_TYPE] = std::to_string(loader_context_->GetType());
-  argv[LOADER_ARG_ID] = std::to_string(loader_context_->GetLoaderId());
-  argv[LOADER_ARG_HYDRA] = loader_context_->IsHydraMode() ? "1" : "0";
-  argv[LOADER_ARG_EXTRA] = loader_context_->GetLoaderExtra();
+  argv[LOADER_ARG_PATH] = loader_context->GetLoaderPath();
+  argv[LOADER_ARG_TYPE] = std::to_string(loader_context->GetType());
+  argv[LOADER_ARG_ID] = std::to_string(loader_context->GetLoaderId());
+  argv[LOADER_ARG_HYDRA] = loader_context->IsHydraMode() ? "1" : "0";
+  argv[LOADER_ARG_EXTRA] = loader_context->GetLoaderExtra();
   return argv;
 }
 
index b2cafaa..b703249 100644 (file)
 #ifndef LAUNCHPAD_PROCESS_POOL_LOADER_EXECUTOR_HH_
 #define LAUNCHPAD_PROCESS_POOL_LOADER_EXECUTOR_HH_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "launchpad-process-pool/executor.hh"
 #include "launchpad-process-pool/loader_context.hh"
+#include "launchpad-process-pool/process_pool.hh"
 
 namespace launchpad {
 
 class LoaderExecutor : public Executor::Delegator,
-                       public Executor {
+                       public Executor,
+                       public ProcessPool::IEvent {
  public:
   LoaderExecutor(const LoaderExecutor&) = delete;
   LoaderExecutor& operator=(const LoaderExecutor&) = delete;
@@ -42,10 +45,13 @@ class LoaderExecutor : public Executor::Delegator,
   ~LoaderExecutor() = default;
 
   void OnExecution() override;
-  std::vector<std::string> CreateLoaderArgv();
+  void OnRequestReceived(std::shared_ptr<AppPacket> app_packet) override;
+  std::vector<std::string> CreateLoaderArgv(
+      const LoaderContext* loader_context);
 
  private:
-  const LoaderContext* loader_context_ = nullptr;
+  std::unique_ptr<ProcessPool> process_pool_;
+  std::vector<std::string> loader_argv_;
 };
 
 }  // namespace launchpad
diff --git a/src/launchpad-process-pool/process_pool.cc b/src/launchpad-process-pool/process_pool.cc
new file mode 100644 (file)
index 0000000..cec1c39
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "launchpad-process-pool/process_pool.hh"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <utility>
+
+#include <parcel.hh>
+#include <procfs.hh>
+
+#include "launchpad-process-pool/log_private.hh"
+
+namespace launchpad {
+
+ProcessPool::ProcessPool(int num_processes, IEvent* event_listener = nullptr)
+    : Executor(this),
+      num_processes_(num_processes),
+      event_listener_(event_listener) {
+  PrepareProcess();
+}
+
+ProcessPool::~ProcessPool() {
+  while (!queue_.empty()) {
+    auto process = std::move(queue_.front());
+    queue_.pop();
+    process->Kill();
+  }
+}
+
+bool ProcessPool::IsPrepared() const {
+  return !queue_.empty();
+}
+
+pid_t ProcessPool::Execute(std::shared_ptr<AppPacket> app_packet) {
+  SetTimer();
+  if (!IsPrepared())
+    return -1;
+
+  auto process = std::move(queue_.front());
+  queue_.pop();
+  process->Send(std::move(app_packet));
+  return process->GetPid();
+}
+
+ProcessPool::Process::Process(pid_t pid, int fd)
+    : pid_(pid), socket_(new Socket(fd)) {
+}
+
+pid_t ProcessPool::Process::GetPid() const {
+  return pid_;
+}
+
+int ProcessPool::Process::Send(std::shared_ptr<AppPacket> app_packet) {
+  _W("Send execution request. process ID: %d", pid_);
+  tizen_base::Parcel parcel;
+  app_packet->WriteToParcel(&parcel);
+  return socket_->Write(parcel.GetData(), parcel.GetDataSize());
+}
+
+void ProcessPool::Process::Kill() {
+  socket_->Close();
+  if (kill(pid_, SIGKILL) == -1) {
+    _E("Failed to send kill signal to the process. pid(%d), errno(%d)",
+        pid_, errno);
+  }
+}
+
+void ProcessPool::OnExecution() {
+  _W("Candidate Process");
+  Procfs::SetComm(getpid(), "process-pool+");
+  close(pipe_fd_[1]);
+  int ret = WaitForRequest(std::make_unique<Socket>(pipe_fd_[0]));
+  exit(ret);
+}
+
+void ProcessPool::PrepareProcess() {
+  int current_process_count = static_cast<int>(queue_.size());
+  for (int i = current_process_count; i < num_processes_; ++i) {
+    pipe_fd_[0] = -1;
+    pipe_fd_[1] = -1;
+    if (pipe(pipe_fd_) == -1) {
+      _E("Failed to create pipe. errno(%d)", errno);
+      return;
+    }
+
+    if (fcntl(pipe_fd_[0], F_SETPIPE_SZ, AppPacket::kMaxPacketSize) == -1)
+      _E("Failed to set pipe size. errno(%d)", errno);
+
+    if (fcntl(pipe_fd_[1], F_SETPIPE_SZ, AppPacket::kMaxPacketSize) == -1)
+      _E("Failed to set pipe size. errno(%d)", errno);
+
+    pid_t pid = Executor::Execute();
+    if (pid == -1) {
+      _E("Failed to fork process. errno(%d)", errno);
+      close(pipe_fd_[0]);
+      close(pipe_fd_[1]);
+      return;
+    }
+
+    close(pipe_fd_[0]);
+    queue_.push(std::make_shared<Process>(pid, pipe_fd_[1]));
+  }
+}
+
+int ProcessPool::WaitForRequest(std::unique_ptr<Socket> socket) {
+  auto app_packet = std::make_shared<AppPacket>();
+  int ret = 0;
+  do {
+    char buf[AppPacket::GetHeaderSize()] = { 0, };
+    ret = socket->Read(buf, sizeof(buf));
+    if (ret != 0) {
+      _E("Failed to read from socket. error(%d)", ret);
+      return -1;
+    }
+
+    tizen_base::Parcel parcel(buf, sizeof(buf));
+    app_packet->ReadFromParcel(&parcel);
+
+    std::vector<uint8_t> data;
+    data.resize(app_packet->GetDataSize());
+    ret = socket->Read(data.data(), app_packet->GetDataSize());
+    if (ret != 0) {
+      _E("Failed to read from socket. error(%d)", ret);
+      return -1;
+    }
+
+    parcel.Write(data.data(), data.size());
+    parcel.ResetReader();
+    app_packet->ReadFromParcel(&parcel);
+  } while (ret != 0);
+
+  if (event_listener_ != nullptr)
+    event_listener_->OnRequestReceived(std::move(app_packet));
+
+  return 0;
+}
+
+void ProcessPool::SetTimer() {
+  if (timer_ != 0)
+    return;
+
+  timer_ = g_timeout_add(1000, OnTimeout, this);
+}
+
+gboolean ProcessPool::OnTimeout(gpointer user_data) {
+  auto* process_pool = static_cast<ProcessPool*>(user_data);
+  process_pool->PrepareProcess();
+  process_pool->timer_ = 0;
+  return G_SOURCE_REMOVE;
+}
+
+}  // namespace launchpad
+
diff --git a/src/launchpad-process-pool/process_pool.hh b/src/launchpad-process-pool/process_pool.hh
new file mode 100644 (file)
index 0000000..302a826
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LAUNCHPAD_PROCESS_POOL_PROCESS_POOL_HH_
+#define LAUNCHPAD_PROCESS_POOL_PROCESS_POOL_HH_
+
+#include <glib.h>
+#include <sys/types.h>
+
+#include <queue>
+#include <memory>
+#include <vector>
+
+#include <app_packet.hh>
+#include <socket.hh>
+
+#include "launchpad-process-pool/executor.hh"
+
+namespace launchpad {
+
+class ProcessPool : public Executor::Delegator,
+                    public Executor {
+ public:
+  class IEvent {
+   public:
+    virtual ~IEvent() = default;
+    virtual void OnRequestReceived(std::shared_ptr<AppPacket> app_packet) = 0;
+  };
+
+  explicit ProcessPool(int num_processes, IEvent* event_listener);
+  virtual ~ProcessPool();
+
+  bool IsPrepared() const;
+  pid_t Execute(std::shared_ptr<AppPacket> app_packet);
+
+ private:
+  class Process {
+   public:
+    Process(pid_t pid, int fd);
+
+    pid_t GetPid() const;
+    int Send(std::shared_ptr<AppPacket> app_packet);
+    void Kill();
+
+   private:
+    pid_t pid_;
+    std::unique_ptr<Socket> socket_;
+  };
+
+  void OnExecution() override;
+
+  void PrepareProcess();
+  int WaitForRequest(std::unique_ptr<Socket> socket);
+  void SetTimer();
+  static gboolean OnTimeout(gpointer user_data);
+
+ private:
+  int num_processes_;
+  IEvent* event_listener_;
+  int pipe_fd_[2] = { -1, -1 };
+  std::queue<std::shared_ptr<Process>> queue_;
+  guint timer_ = 0;
+};
+
+}  // namespace launchpad
+
+#endif  // LAUNCHPAD_PROCESS_POOL_PROCESS_POOL_HH_
index ec8a4d6..0b2dd45 100644 (file)
@@ -22,6 +22,7 @@
 #include <fstream>
 
 #include <exception.hh>
+#include <procfs.hh>
 
 #include "launchpad-process-pool/log_private.hh"
 
@@ -54,22 +55,9 @@ void Worker::Add(std::shared_ptr<Worker::Job >job) {
   queue_->Push(std::move(job));
 }
 
-void Worker::SetComm() {
-  const std::string path = "/proc/" + std::to_string(gettid()) + "/comm";
-  std::ofstream comm_file;
-  comm_file.open(path);
-  if (!comm_file.is_open()) {
-    _E("Failed to open %s", path.c_str());
-    return;
-  }
-
-  comm_file << name_;
-  comm_file.close();
-}
-
 void Worker::RunThread() {
   _W("BEGIN");
-  SetComm();
+  Procfs::SetComm(gettid(), name_);
   while (true) {
     auto job = queue_->WaitAndPop();
     job->Do();
index 32afdaf..c8dff3f 100644 (file)
@@ -41,7 +41,6 @@ class Worker {
   void Add(std::shared_ptr<Worker::Job> job);
 
  private:
-  void SetComm();
   void RunThread();
 
  private:
index b62e8c5..e655544 100644 (file)
@@ -18,6 +18,7 @@ APPLY_PKG_CONFIG(${TARGET_LAUNCHPAD_COMMON} PUBLIC
   GIO_DEPS
   INIPARSER_DEPS
   VCONF_DEPS
+  PARCEL_DEPS
 )
 
 TARGET_LINK_LIBRARIES(${TARGET_LAUNCHPAD_COMMON} PUBLIC "-ldl")
diff --git a/src/lib/launchpad-common/app_packet.cc b/src/lib/launchpad-common/app_packet.cc
new file mode 100644 (file)
index 0000000..519ac4b
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "launchpad-common/app_packet.hh"
+
+#include <utility>
+
+#include <parcel.hh>
+
+namespace launchpad {
+
+AppPacket::AppPacket(int command, int option, std::vector<uint8_t> data)
+    : command_(command),
+      option_(option),
+      data_size_(static_cast<int>(data.size())),
+      data_(std::move(data)) {}
+
+void AppPacket::WriteToParcel(tizen_base::Parcel* parcel) const {
+  parcel->WriteInt32(command_);
+  parcel->WriteInt32(option_);
+  parcel->WriteInt32(data_size_);
+  if (data_size_ > 0)
+    parcel->Write(data_.data(), data_.size());
+}
+
+void AppPacket::ReadFromParcel(tizen_base::Parcel* parcel) {
+  parcel->ReadInt32(&command_);
+  parcel->ReadInt32(&option_);
+  parcel->ReadInt32(&data_size_);
+  if (data_size_ > 0) {
+    data_.resize(data_size_);
+    parcel->Read(data_.data(), data_.size());
+  }
+}
+
+int AppPacket::GetCommand() const {
+  return command_;
+}
+
+int AppPacket::GetOption() const {
+  return option_;
+}
+
+int AppPacket::GetDataSize() const {
+  return data_size_;
+}
+
+const std::vector<uint8_t>& AppPacket::GetData() const {
+  return data_;
+}
+
+}  // namespace launchpad
diff --git a/src/lib/launchpad-common/app_packet.hh b/src/lib/launchpad-common/app_packet.hh
new file mode 100644 (file)
index 0000000..983ae2b
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIB_LAUNCHPAD_COMMON_APP_PACKET_HH_
+#define LIB_LAUNCHPAD_COMMON_APP_PACKET_HH_
+
+#include <cstdint>
+#include <vector>
+
+#include <parcelable.hh>
+
+#undef EXPORT_API
+#define EXPORT_API __attribute__((visibility("default")))
+
+namespace launchpad {
+
+class EXPORT_API AppPacket : public tizen_base::Parcelable {
+ public:
+  AppPacket() = default;
+  AppPacket(int command, int option, std::vector<uint8_t> data);
+  virtual ~AppPacket() = default;
+
+  void WriteToParcel(tizen_base::Parcel* parcel) const override;
+  void ReadFromParcel(tizen_base::Parcel* parcel) override;
+
+  static constexpr size_t GetHeaderSize() {
+    return sizeof(int) + sizeof(int) + sizeof(int);
+  }
+
+  int GetCommand() const;
+  int GetOption() const;
+  int GetDataSize() const;
+  const std::vector<uint8_t>& GetData() const;
+
+  static constexpr int kMaxPacketSize = 131071;
+
+ private:
+  int command_ = 0;
+  int option_ = 0;
+  int data_size_ = 0;
+  std::vector<uint8_t> data_;
+};
+
+}  // namespace launchpad
+
+#endif  // LIB_LAUNCHPAD_COMMON_APP_PACKET_HH_
index 6b5cff3..c1fad50 100644 (file)
@@ -8,6 +8,6 @@ includedir=@INCLUDE_INSTALL_DIR@
 Name: liblaunchpad-common
 Description: launchpad common library
 Version: @VERSION@
-Requires: bundle dlog
+Requires: bundle dlog parcel
 Libs: -L${libdir} -llaunchpad-common
 Cflags: -I${includedir} -I${includedir}/launchpad-common
index 54009e2..eaf3605 100644 (file)
@@ -127,4 +127,17 @@ std::string Procfs::GetAttrCurrent(pid_t pid) {
   return result;
 }
 
+void Procfs::SetComm(pid_t pid, const std::string& comm) {
+  const std::string path = "/proc/" + std::to_string(pid) + "/comm";
+  std::ofstream comm_file;
+  comm_file.open(path);
+  if (!comm_file.is_open()) {
+    _E("Failed to open %s", path.c_str());
+    return;
+  }
+
+  comm_file << comm;
+  comm_file.close();
+}
+
 }  // namespace launchpad
index 4c45e7a..71f3318 100644 (file)
@@ -31,6 +31,7 @@ class EXPORT_API Procfs {
   static void GetMemoryUsage(uint32_t* usage);
   static void GetPssMemory(pid_t pid, uint64_t* mem_pss);
   static std::string GetAttrCurrent(pid_t pid);
+  static void SetComm(pid_t pid, const std::string& comm);
 };
 
 }  // namespace launchpad