Refactor launchpad debug 04/290404/6
authorHwankyu Jhun <h.jhun@samsung.com>
Fri, 24 Mar 2023 05:13:21 +0000 (05:13 +0000)
committerHwankyu Jhun <h.jhun@samsung.com>
Fri, 24 Mar 2023 06:24:55 +0000 (06:24 +0000)
The launchpad debug is implemented using C++ language.

Change-Id: I13ed4cb60cfcf356d52748d3a2f3d53182ca2d23
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/launchpad-process-pool/debug.cc
src/launchpad-process-pool/debug.hh
src/launchpad-process-pool/debugger_info.cc
src/launchpad-process-pool/debugger_info.hh
src/launchpad-process-pool/launchpad.cc
src/launchpad-process-pool/launchpad_debug.cc [deleted file]
src/launchpad-process-pool/launchpad_debug.h [deleted file]
src/launchpad-process-pool/util.cc
src/launchpad-process-pool/util.hh
tests/launchpad-process-pool-unittest/src/test_launchpad.cc

index 0d2f90b..4d70c91 100644 (file)
 
 #include "launchpad-process-pool/debug.hh"
 
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <fstream>
+#include <utility>
 
+#include "lib/common/inc/key.h"
 #include "lib/common/inc/launchpad_common.h"
 
+namespace fs = std::filesystem;
+
 namespace launchpad {
+namespace {
+
+constexpr const char kAsanAppListPath[] =
+    "/opt/usr/share/aul/debug/.asan_app_list";
+constexpr const char kDebuggerInfoPath[] = "/run/share/aul";
+
+std::vector<std::string> GetStringArray(const tizen_base::Bundle& b,
+    const std::string& key) {
+  std::vector<std::string> values;
+  if (b.GetType(key) & BUNDLE_TYPE_ARRAY) {
+    values = b.GetStringArray(key);
+  } else {
+    std::string value = b.GetString(key);
+    if (!value.empty())
+      values.push_back(std::move(value));
+  }
+
+  return values;
+}
+
+}  // namespace
+
+Debug& Debug::GetInst() {
+  static Debug inst;
+  inst.Init();
+  return inst;
+}
+
+void Debug::Dispose() {
+  if (disposed_)
+    return;
+
+  file_monitor_.reset();
+  disposed_ = true;
+}
+
+void Debug::Load() {
+  if (!debugger_infos_.empty())
+    return;
+
+  DebuggerInfoInflator inflator;
+  debugger_infos_ = inflator.Inflate(kDebuggerInfoPath);
+}
+
+void Debug::PrepareDebugger(const tizen_base::Bundle& b) {
+  auto debugger = b.GetString(AUL_K_SDK);
+  if (debugger.empty())
+    return;
+
+  _D("[DEBUG] Debugger: %s", debugger.c_str());
+  auto found = debugger_infos_.find(debugger);
+  if (found == debugger_infos_.end())
+    return;
+
+  debugger_info_ = found->second;
+  if (debugger == "ASAN")
+    setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
+
+  ParseAndRedirectStandardFds(b);
+  RemoveFiles(debugger_info_->GetUnlinkList());
+
+  for (const auto& extra_env : debugger_info_->GetExtraEnvList())
+    ParseAndSetEnvironment(b, extra_env);
+
+  debug_argv_ = debugger_info_->GetDefaultOptList();
+  debug_argv_.insert(debug_argv_.begin(), debugger_info_->GetExe());
+  for (const auto& extra_key : debugger_info_->GetExtraKeyList())
+    ParseAndAddArgv(b, extra_key);
+
+  for (const auto& last_extra_key : debugger_info_->GetLastExtraKeyList())
+    ParseAndAddExtraArgv(b, last_extra_key);
+}
+
+void Debug::ChangeMountNamespace() {
+  auto target_pid = std::getenv("TARGET_PID");
+  if (target_pid == nullptr)
+    return;
+
+  std::string mnt_path = "/proc/" + std::string(target_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;
+  }
+
+  int ret = ::setns(fd, CLONE_NEWNS);
+  close(fd);
+  if (ret != 0) {
+    _E("setns() is failed. errno(%d)", errno);
+    return;
+  }
+
+  _D("setns() is successful");
+}
+
+void Debug::CheckWebAppDebugging(const tizen_base::Bundle& b) {
+  if (b.GetType(AUL_K_DEBUG) != BUNDLE_TYPE_NONE)
+    setenv("TIZEN_DEBUGGING_PORT", "1", 1);
+}
+
+bool Debug::CheckAsanApp(const std::string& appid) {
+  return asan_app_map_.find(appid) != asan_app_map_.end();
+}
+
+void Debug::CheckAndSetAsanActivation(const std::string& appid) {
+  if (CheckAsanApp(appid)) {
+    _W("Set TIZEN_ASAN_ACTIVATION. appid: %s", appid.c_str());
+    setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
+  }
+}
+
+std::vector<std::string> Debug::GetExtraArgv() const {
+  return extra_argv_;
+}
+
+std::vector<std::string> Debug::GetArgv() const {
+  return debug_argv_;
+}
+
+bool Debug::ShouldAttach() const {
+  if (!debugger_info_)
+    return false;
+
+  return debugger_info_->GetAttachInfo() == "true";
+}
+
+Debug::~Debug() {
+  Dispose();
+}
+
+void Debug::Init() {
+  if (!disposed_)
+    return;
+
+  file_monitor_ = std::make_unique<FileMonitor>(kAsanAppListPath, this);
+  disposed_ = false;
+}
+
+void Debug::RemoveFiles(const std::vector<std::string>& files) {
+  for (const auto& file : files) {
+    if (fs::exists(file)) {
+      _D("[DEBUG] file: %s", file.c_str());
+      fs::remove(file);
+    }
+  }
+}
+
+void Debug::ParseAndSetEnvironment(const tizen_base::Bundle& b,
+    const std::string& key) {
+  _D("[DEBUG] key: %s", key.c_str());
+  std::vector<std::string> values = GetStringArray(b, key);
+  if (values.empty())
+    return;
+
+  std::string env;
+  for (const auto& value : values) {
+    if (!env.empty())
+      env += ",";
+
+    env += value;
+  }
+
+  const_cast<tizen_base::Bundle&>(b).Delete(key);
+  _D("[DEBUG] value: %s", env.c_str());
+  setenv(key.c_str(), env.c_str(), 1);
+}
+
+void Debug::ParseAndAddArgv(const tizen_base::Bundle& b,
+    const std::string& key) {
+  _D("[DEBUG] key: %s", key.c_str());
+  std::vector<std::string> values = GetStringArray(b, key);
+  if (values.empty())
+    return;
+
+  for (const auto& arg : values) {
+    debug_argv_.push_back(arg);
+    if (key == "__DLP_ATTACH_ARG__" && isdigit(arg[0])) {
+      _D("[DEBUG] TARGET_PID: %s", arg.c_str());
+      setenv("TARGET_PID", arg.c_str(), 1);
+    }
+  }
+
+  const_cast<tizen_base::Bundle&>(b).Delete(key);
+}
+
+void Debug::ParseAndAddExtraArgv(const tizen_base::Bundle& b,
+    const std::string& key) {
+  _D("[DEBUG] key: %s", key.c_str());
+  std::vector<std::string> values = GetStringArray(b, key);
+  if (values.empty()) return;
+
+  for (const auto& arg : values)
+    extra_argv_.push_back(arg);
+
+  const_cast<tizen_base::Bundle&>(b).Delete(key);
+}
+
+void Debug::ParseAndRedirectStandardFds(const tizen_base::Bundle& b) {
+  pid_t caller_pid = GetCallerPid(b);
+  if (caller_pid < 0)
+    return;
+
+  // stdin
+  std::string path = "/proc/" + std::to_string(caller_pid) + "/fd/";
+  int fd = open((path + std::to_string(STDIN_FILENO)).c_str(), O_RDONLY);
+  if (fd < 0) {
+    _E("Failed to open STDIN file descriptor. errno(%d)", errno);
+    return;
+  }
+
+  dup2(fd, STDIN_FILENO);
+  close(fd);
+
+  // stdout
+  fd = open((path + std::to_string(STDOUT_FILENO)).c_str(), O_WRONLY);
+  if (fd < 0) {
+    _E("Failed to open STDOUT file descriptor. errno(%d)", errno);
+    return;
+  }
+
+  dup2(fd, STDOUT_FILENO);
+  close(fd);
+
+  // stdout
+  fd = open((path + std::to_string(STDERR_FILENO)).c_str(), O_WRONLY);
+  if (fd < 0) {
+    _E("Failed to open STDERR file descriptor. errno(%d)", errno);
+    return;
+  }
+
+  dup2(fd, STDERR_FILENO);
+  close(fd);
+}
+
+pid_t Debug::GetCallerPid(const tizen_base::Bundle& b) {
+  auto pid_str = b.GetString(AUL_K_ORG_CALLER_PID);
+  if (pid_str.empty())
+    pid_str = b.GetString(AUL_K_CALLER_PID);
 
-AsanAppChecker::AsanAppChecker() : file_monitor_(kAsanAppListPath, this) {}
+  if (pid_str.empty())
+    return -1;
 
-void AsanAppChecker::Update() {
+  return std::stoi(pid_str);
+}
+
+void Debug::OnFileChanged(FileMonitor::FileMonitorEvent event) {
+  _W("%s was changed. event(%d)", kAsanAppListPath, static_cast<int>(event));
   asan_app_map_.clear();
   std::ifstream if_stream;
   if_stream.open(kAsanAppListPath);
@@ -40,14 +293,4 @@ void AsanAppChecker::Update() {
   }
 }
 
-bool AsanAppChecker::CheckAsanApp(const std::string& appid) const {
-  return asan_app_map_.find(appid) != asan_app_map_.end();
-}
-
-void AsanAppChecker::OnFileChanged(
-    launchpad::FileMonitor::FileMonitorEvent event) {
-  _W("%s was changed. event(%d)", kAsanAppListPath, static_cast<int>(event));
-  Update();
-}
-
 }  // namespace launchpad
index d0ae3a1..48212d0 100644 (file)
  * limitations under the License.
  */
 
-#ifndef DEBUG_HH_
-#define DEBUG_HH_
+#ifndef LAUNCHPAD_PROCESS_POOL_DEBUG_HH_
+#define LAUNCHPAD_PROCESS_POOL_DEBUG_HH_
 
+#include <bundle_cpp.h>
+
+#include <list>
+#include <memory>
 #include <string>
+#include <unordered_map>
 #include <unordered_set>
+#include <vector>
 
-#include <launchpad-process-pool/file_monitor.hh>
+#include "launchpad-process-pool/debugger_info.hh"
+#include "launchpad-process-pool/file_monitor.hh"
 
 namespace launchpad {
 
-class AsanAppChecker : public launchpad::FileMonitor::IEvent {
+class Debug : public FileMonitor::IEvent {
  public:
-  AsanAppChecker();
-  bool CheckAsanApp(const std::string& appid) const;
+  Debug(const Debug&) = delete;
+  Debug& operator = (const Debug&) = delete;
+  Debug(Debug&&) = delete;
+  Debug& operator = (Debug&&) = delete;
+
+  static Debug& GetInst();
+  void Init();
+  void Dispose();
+  void Load();
+  void PrepareDebugger(const tizen_base::Bundle& b);
+  std::vector<std::string> GetExtraArgv() const;
+  std::vector<std::string> GetArgv() const;
+  bool ShouldAttach() const;
+  bool CheckAsanApp(const std::string& appid);
+  void CheckAndSetAsanActivation(const std::string& appid);
+
+  static void ChangeMountNamespace();
+  static void CheckWebAppDebugging(const tizen_base::Bundle& b);
 
  private:
-  void Update();
+  Debug() = default;
+  ~Debug();
+
+  void RemoveFiles(const std::vector<std::string>& files);
+  void ParseAndSetEnvironment(
+      const tizen_base::Bundle& b, const std::string& key);
+  void ParseAndAddArgv(const tizen_base::Bundle& b, const std::string& key);
+  void ParseAndAddExtraArgv(const tizen_base::Bundle& b,
+      const std::string& key);
+  void ParseAndRedirectStandardFds(const tizen_base::Bundle& b);
+  pid_t GetCallerPid(const tizen_base::Bundle& b);
+
   void OnFileChanged(launchpad::FileMonitor::FileMonitorEvent event) override;
 
+ private:
+  bool disposed_ = true;
+  DebuggerInfoPtr debugger_info_;
+  std::unordered_map<std::string, DebuggerInfoPtr> debugger_infos_;
+  std::vector<std::string> debug_argv_;
+  std::vector<std::string> extra_argv_;
   std::unordered_set<std::string> asan_app_map_;
-  static constexpr const char kAsanAppListPath[] =
-      "/opt/usr/share/aul/debug/.asan_app_list";
-  launchpad::FileMonitor file_monitor_;
+  std::unique_ptr<launchpad::FileMonitor> file_monitor_;
 };
 
 }  // namespace launchpad
 
-#endif  // DEBUG_HH_
+#endif  // LAUNCHPAD_PROCESS_POOL_DEBUG_HH_
index 5ae58bd..b82890f 100644 (file)
@@ -50,82 +50,6 @@ constexpr const char kTagDefaultOpt[] = "DEFAULT_OPT";
 
 namespace fs = std::filesystem;
 
-void DebuggerInfoInflator::Parse(
-    std::vector<DebuggerInfoPtr>& debugger_info_list,
-    const fs::path& path) {
-  std::ifstream fp;
-  fp.open(path);
-  if (fp.fail())
-    return;
-
-  DebuggerInfoPtr info;
-  std::string input;
-  while (std::getline(fp, input)) {
-    std::istringstream ss(input);
-    std::string tok1, tok2;
-    if (!(ss >> tok1))
-      continue;
-
-    if (strcasecmp(kTagDebugger, tok1.c_str()) == 0) {
-      if (info != nullptr) {
-        _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
-        debugger_info_list.push_back(std::move(info));
-      }
-
-      info = std::make_unique<DebuggerInfo>();
-      continue;
-    }
-
-    if (!(ss >> tok2))
-      continue;
-    if (tok1.front() == '#' || info == nullptr)
-      continue;
-
-    std::string key;
-    std::transform(tok1.begin(), tok1.end(), std::back_inserter(key),
-                   [](char ch) { return toupper(ch); });
-    if (kTagName == key) {
-      info->name_ = std::move(tok2);
-    } else if (kTagExe == key) {
-      fs::path file(tok2);
-      if (fs::exists(file) == false) {
-        _E("Failed to access %s", tok2.c_str());
-        info.reset();
-        continue;
-      }
-
-      info->exe_ = std::move(tok2);
-    } else if (kTagAppType == key) {
-      std::string line = std::move(tok2);
-      do {
-        auto tokens = Split(line, " |\t\r\n");
-        for (auto& token : tokens) {
-          _E("types: %s", token.c_str());
-          info->app_types_.push_back(std::move(token));
-        }
-      } while (std::getline(ss, line));
-    } else if (kTagExtraKey == key) {
-      info->extra_key_list_.push_back(std::move(tok2));
-    } else if (kTagExtraEnv == key) {
-      info->extra_env_list_.push_back(std::move(tok2));
-    } else if (kTagUnlink == key) {
-      info->unlink_list_.push_back(std::move(tok2));
-    } else if (kTagAttach == key) {
-      info->attach_ = std::move(tok2);
-    } else if (kTagLastExtraKey == key) {
-      info->last_extra_key_list_.push_back(std::move(tok2));
-    } else if (kTagDefaultOpt == key) {
-      info->default_opt_list_.push_back(std::move(tok2));
-    }
-  }
-
-  fp.close();
-  if (info) {
-    _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
-    debugger_info_list.push_back(std::move(info));
-  }
-}
-
 const std::string& DebuggerInfo::GetName() const {
   return name_;
 }
@@ -162,20 +86,95 @@ const std::vector<std::string>& DebuggerInfo::GetDefaultOptList() const {
   return default_opt_list_;
 }
 
-std::vector<DebuggerInfoPtr> DebuggerInfoInflator::Inflate(
+std::unordered_map <std::string, DebuggerInfoPtr> DebuggerInfoInflator::Inflate(
     const std::string_view path) {
-  fs::path p(path);
-  if (fs::is_directory(p) == false)
-    return {};
+  fs::path input_path(path);
+  if (fs::is_directory(input_path) == false)
+    return debugger_infos_;
 
-  std::vector<DebuggerInfoPtr> result;
-  for (auto& entry : fs::directory_iterator(p)) {
+  for (auto& entry : fs::directory_iterator(input_path)) {
     fs::path file(entry.path());
     if (file.extension() == ".debugger")
-      Parse(result, file);
+      Parse(file);
+  }
+
+  return debugger_infos_;
+}
+
+void DebuggerInfoInflator::Parse(const fs::path& path) {
+  std::ifstream input_file(path);
+  if (!input_file.is_open())
+    return;
+
+  DebuggerInfoPtr current_info;
+  std::string input;
+  while (std::getline(input_file, input)) {
+    std::istringstream ss(input);
+    std::string token1;
+    if (!(ss >> token1))
+      continue;
+
+    std::string key = ToUpper(token1);
+    if (key == kTagDebugger) {
+      if (current_info != nullptr)
+        InsertDebuggerInfo(std::move(current_info));
+
+      current_info = std::make_unique<DebuggerInfo>();
+      continue;
+    }
+
+    if (key.front() == '#' || current_info == nullptr)
+      continue;
+
+    std::string token2;
+    if (!(ss >> token2))
+      continue;
+
+    if (key == kTagName) {
+      current_info->name_ = std::move(token2);
+    } else if (key == kTagExe) {
+      current_info->exe_ = std::move(token2);
+    } else if (key == kTagAppType) {
+      ParseAndSetAppTypes(current_info.get(), ss, std::move(token2));
+    } else if (key == kTagExtraKey) {
+      current_info->extra_key_list_.push_back(std::move(token2));
+    } else if (key == kTagExtraEnv) {
+      current_info->extra_env_list_.push_back(std::move(token2));
+    } else if (key == kTagUnlink) {
+      current_info->unlink_list_.push_back(std::move(token2));
+    } else if (key == kTagAttach) {
+      current_info->attach_ = std::move(token2);
+    } else if (key == kTagLastExtraKey) {
+      current_info->last_extra_key_list_.push_back(std::move(token2));
+    } else if (key == kTagDefaultOpt) {
+      current_info->default_opt_list_.push_back(std::move(token2));
+    }
   }
 
-  return result;
+  if (current_info != nullptr)
+    InsertDebuggerInfo(std::move(current_info));
+
+  input_file.close();
+}
+
+void DebuggerInfoInflator::ParseAndSetAppTypes(DebuggerInfo* info,
+    std::istringstream& ss, std::string line) {
+  do {
+    auto tokens = Split(line, " |\t\r\n");
+    for (auto& token : tokens) {
+      _D("app-type: %s", token.c_str());
+      info->app_types_.push_back(std::move(token));
+    }
+  } while (std::getline(ss, line));
+}
+
+void DebuggerInfoInflator::InsertDebuggerInfo(DebuggerInfoPtr info) {
+  if (debugger_infos_.find(info->name_) != debugger_infos_.end())
+    return;
+
+  _D("name: %s, exe: %s", info->name_.c_str(), info->exe_.c_str());
+  std::string name = info->name_;
+  debugger_infos_[std::move(name)] = std::move(info);
 }
 
 }  // namespace launchpad
index 83a578d..b02bdb1 100644 (file)
  * limitations under the License.
  */
 
-#ifndef DEBUGGER_INFO_HH_
-#define DEBUGGER_INFO_HH_
+#ifndef LAUNCHPAD_PROCESS_POOL_DEBUGGER_INFO_HH_
+#define LAUNCHPAD_PROCESS_POOL_DEBUGGER_INFO_HH_
 
 #include <filesystem>
 #include <memory>
 #include <string>
 #include <string_view>
+#include <unordered_map>
 #include <vector>
 
 namespace launchpad {
@@ -55,12 +56,19 @@ using DebuggerInfoPtr = std::shared_ptr<DebuggerInfo>;
 
 class DebuggerInfoInflator {
  public:
-  std::vector<DebuggerInfoPtr> Inflate(const std::string_view path);
+  std::unordered_map<std::string, DebuggerInfoPtr> Inflate(
+      const std::string_view path);
+
+ private:
+  void Parse(const std::filesystem::path& path);
+  void ParseAndSetAppTypes(DebuggerInfo* info, std::istringstream& ss,
+      std::string line);
+  void InsertDebuggerInfo(DebuggerInfoPtr info);
+
  private:
-  void Parse(std::vector<DebuggerInfoPtr>& debugger_info_list,
-             const std::filesystem::path& path);
+  std::unordered_map<std::string, DebuggerInfoPtr> debugger_infos_;
 };
 
 }  // namespace launchpad
 
-#endif  // DEBUGGER_INFO_HH_
+#endif  // LAUNCHPAD_PROCESS_POOL_DEBUGGER_INFO_HH_
index 4d9a8fb..1acda44 100644 (file)
 
 #include <procfs.hh>
 
-#include "launchpad-process-pool/debug.hh"
 #include "launchpad-process-pool/launcher_info.hh"
 #include "launchpad-process-pool/launchpad_config.h"
-#include "launchpad-process-pool/launchpad_debug.h"
 #include "launchpad-process-pool/launchpad_inotify.h"
 #include "launchpad-process-pool/launchpad_io_channel.h"
-#include "launchpad-process-pool/loader_info.hh"
 #include "launchpad-process-pool/slot_info.h"
 #include "lib/common/inc/key.h"
 #include "lib/common/inc/launchpad_common.h"
@@ -57,7 +54,9 @@
 #include "lib/common/inc/launchpad_types.h"
 #include "lib/common/inc/perf.h"
 
+#include "launchpad-process-pool/debug.hh"
 #include "launchpad-process-pool/dbus.hh"
+#include "launchpad-process-pool/loader_info.hh"
 #include "launchpad-process-pool/log.hh"
 #include "launchpad-process-pool/memory_monitor.hh"
 #include "launchpad-process-pool/signal_manager.hh"
@@ -278,7 +277,6 @@ io_channel_h __logger_channel;
 io_channel_h __label_monitor_channel;
 io_channel_h __launchpad_channel;
 int __client_fd = -1;
-launchpad::AsanAppChecker __asan_app_checker;
 std::unique_ptr<launchpad::Worker> cleaner;
 SigchldHandler sigchld_handler;
 
@@ -1154,170 +1152,73 @@ static int __normal_fork_exec(int argc, char** argv, const char* app_path) {
   return 0;
 }
 
-static int __create_launcher_argv(int* argc, char*** argv,
-    const char* app_type) {
-  int launcher_argc;
-  char** launcher_argv;
-  launchpad::LauncherInfoPtr launcher_info;
-  const char* exe;
-  int i;
-
-  auto it = std::find_if(
-      launcher_info_list.begin(), launcher_info_list.end(),
+static std::vector<std::string> GetLauncherArgv(
+    const std::string& app_type) {
+  std::vector<std::string> argv;
+  auto found = std::find_if(launcher_info_list.begin(),
+      launcher_info_list.end(),
       [app_type](const launchpad::LauncherInfoPtr& info) -> bool {
         return std::find_if(info->GetAppTypes().begin(),
-                            info->GetAppTypes().end(),
-                            [app_type](const std::string& type) -> bool {
-                              return strcmp(type.c_str(), app_type) == 0;
-                            }) != info->GetAppTypes().end();
+            info->GetAppTypes().end(),
+            [app_type](const std::string& type) -> bool {
+              return type == app_type;
+            }) != info->GetAppTypes().end();
       });
+  if (found == launcher_info_list.end())
+    return argv;
 
-  if (it == launcher_info_list.end())
-    return 0;
-
-  launcher_info = *it;
-  exe = launcher_info->GetExe().c_str();
-
-  auto& extra_args = launcher_info->GetExtraArgs();
-  launcher_argc = extra_args.size() + 1;
-  launcher_argv = static_cast<char**>(calloc(launcher_argc, sizeof(char*)));
-  if (launcher_argv == nullptr) {
-    _E("out of memory");
-    return -1;
-  }
-
-  i = LOADER_ARG_PATH;
-  launcher_argv[i++] = strdup(exe);
-
-  for (auto& extra_arg : extra_args) {
-    launcher_argv[i++] = strdup(extra_arg.c_str());
-  }
-
-  *argc = launcher_argc;
-  *argv = launcher_argv;
-
-  return 0;
-}
-
-static void __destroy_launcher_argv(int argc, char** argv) {
-  int i;
-
-  if (argv == nullptr)
-    return;
-
-  for (i = 0; i < argc; i++)
-    free(argv[i]);
-  free(argv);
+  auto launcher_info = *found;
+  argv.insert(argv.end(), launcher_info->GetExe());
+  argv.insert(argv.end(), launcher_info->GetExtraArgs().begin(),
+      launcher_info->GetExtraArgs().end());
+  return argv;
 }
 
-static int __create_app_argv(int* argc, char*** argv, const char* app_path,
-    bundle* kb, const char* app_type) {
-  int new_argc;
-  char** new_argv;
-  bool attach = false;
-  struct app_arg debug_arg = { 0, };
-  struct app_arg launcher_arg = { 0, };
-  struct app_arg arg = { 0, };
-  struct app_arg debug_extra_arg = { 0, };
-  int ret;
-  int i;
-  int c;
-
-  ret = _debug_create_argv(&debug_arg.argc, &debug_arg.argv, &attach);
-  if (ret < 0) {
-    _E("Failed to create debugger argv");
-    return -1;
-  }
-
-  if (attach) {
-    *argc = debug_arg.argc;
-    *argv = debug_arg.argv;
-    return 0;
-  }
+static std::vector<std::string> CreateAppArgv(const std::string& app_path,
+    const tizen_base::Bundle& b, const std::string& app_type) {
+  auto& inst = launchpad::Debug::GetInst();
+  std::vector<std::string> argv = inst.GetArgv();
+  if (inst.ShouldAttach())
+    return argv;
 
-  ret = _debug_create_extra_argv(&debug_extra_arg.argc, &debug_extra_arg.argv);
-  if (ret < 0) {
-    _E("Failed to create debugger extra argv");
-    _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
-    return -1;
-  }
+  auto launcher_argv = GetLauncherArgv(app_type);
+  if (!launcher_argv.empty())
+    argv.insert(argv.end(), launcher_argv.begin(), launcher_argv.end());
 
-  ret =
-      __create_launcher_argv(&launcher_arg.argc, &launcher_arg.argv, app_type);
-  if (ret < 0) {
-    _E("Failed to create launcher argv");
-    _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
-    _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
-    return -1;
-  }
+  auto exported_argv = b.Export();
+  exported_argv[LOADER_ARG_PATH] = app_path;
+  if (!exported_argv.empty())
+    argv.insert(argv.end(), exported_argv.begin(), exported_argv.end());
 
-  arg.argc = bundle_export_to_argv(kb, &arg.argv);
-  if (arg.argc <= 0) {
-    _E("Failed to export bundle");
-    __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
-    _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
-    _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
-    return -1;
-  }
-  arg.argv[LOADER_ARG_PATH] = strdup(app_path);
-
-  new_argc =
-      debug_arg.argc + launcher_arg.argc + arg.argc + debug_extra_arg.argc;
-  if (new_argc == arg.argc) {
-    *argc = arg.argc;
-    *argv = arg.argv;
-    return 0;
-  }
+  auto extra_argv = inst.GetExtraArgv();
+  if (!extra_argv.empty())
+    argv.insert(argv.end(), extra_argv.begin(), extra_argv.end());
 
-  new_argv = reinterpret_cast<char**>(calloc(new_argc + 1, sizeof(char*)));
-  if (new_argv == nullptr) {
-    _E("out of memory");
-    free(arg.argv[LOADER_ARG_PATH]);
-    bundle_free_exported_argv(arg.argc, &arg.argv);
-    __destroy_launcher_argv(launcher_arg.argc, launcher_arg.argv);
-    _debug_destroy_argv(debug_extra_arg.argc, debug_extra_arg.argv);
-    _debug_destroy_argv(debug_arg.argc, debug_arg.argv);
-    return -1;
-  }
-
-  c = static_cast<int>(LOADER_ARG_PATH);
-  for (i = 0; i < debug_arg.argc; i++)
-    new_argv[c++] = debug_arg.argv[i];
-  for (i = 0; i < launcher_arg.argc; i++)
-    new_argv[c++] = launcher_arg.argv[i];
-  for (i = 0; i < arg.argc; i++)
-    new_argv[c++] = arg.argv[i];
-  for (i = 0; i < debug_extra_arg.argc; i++)
-    new_argv[c++] = debug_extra_arg.argv[i];
-
-  *argc = new_argc;
-  *argv = new_argv;
-
-  return 0;
+  return argv;
 }
 
 static void __real_launch(const char* app_path, bundle* kb,
     appinfo_t* menu_info) {
-  int app_argc = 0;
-  char** app_argv;
-  int i;
-  int ret;
-
-  if (bundle_get_val(kb, AUL_K_DEBUG) != nullptr)
-    setenv("TIZEN_DEBUGGING_PORT", "1", 1);
+  tizen_base::Bundle b(kb, false, false);
+  launchpad::Debug::CheckWebAppDebugging(b);
 
-  ret = __create_app_argv(&app_argc, &app_argv, app_path, kb,
-                          menu_info->app_type);
-  if (ret < 0) {
-    _E("Failed to create app argv");
+  std::vector<std::string> argv = CreateAppArgv(app_path, b,
+      menu_info->app_type);
+  char** app_argv = static_cast<char**>(calloc(argv.size() + 1, sizeof(char*)));
+  if (app_argv == nullptr) {
+    _E("Out of memory");
     exit(-1);
   }
 
-  for (i = 0; i < app_argc; i++)
+  int app_argc = argv.size();
+  for (int i = 0; i < app_argc; i++) {
+    app_argv[i] = const_cast<char*>(argv[i].c_str());
     SECURE_LOGD("input argument %d : %s##", i, app_argv[i]);
+  }
 
   PERF("setup argument done");
   __normal_fork_exec(app_argc, app_argv, app_path);
+  free(app_argv);
 }
 
 static int __prepare_exec(const char* appid, const char* app_path,
@@ -1358,7 +1259,7 @@ static int __prepare_exec(const char* appid, const char* app_path,
     return PAD_ERR_FAILED;
 
   if (bundle_get_type(kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
-    _debug_change_mount_namespace();
+    launchpad::Debug::ChangeMountNamespace();
 
   /* SET PRIVILEGES*/
   enabled_light_user = bundle_get_val(kb, AUL_K_ENABLED_LIGHT_USER);
@@ -1419,13 +1320,11 @@ static int __exec_app_process(void* arg) {
   PERF("fork done");
   _D("lock up test log(no error) : fork done");
 
-  if (bundle_get_type(launch_arg->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
-    _debug_prepare_debugger(launch_arg->kb);
+  tizen_base::Bundle b(launch_arg->kb, false, false);
+  if (b.GetType(AUL_K_SDK) != BUNDLE_TYPE_NONE)
+    launchpad::Debug::GetInst().PrepareDebugger(b);
 
-  if (__asan_app_checker.CheckAsanApp(launch_arg->appid)) {
-    _W("%s TIZEN_ASAN_ACTIVATION", launch_arg->appid);
-    setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
-  }
+  launchpad::Debug::GetInst().CheckAndSetAsanActivation(launch_arg->appid);
 
   launchpad::SignalManager::GetInst().UnblockSigchld();
   _delete_sock_path(getpid(), getuid());
@@ -2493,7 +2392,7 @@ static void __handle_direct_launch(request_h request) {
 
 static void __fork_processing(request_h request) {
   if (bundle_get_type(request->kb, AUL_K_SDK) != BUNDLE_TYPE_NONE)
-    _debug_init();
+    launchpad::Debug::GetInst().Load();
 
   _W("appid: %s", request->menu_info->appid);
   request->pid = __launch_directly(request->menu_info->appid, request->app_path,
@@ -2510,7 +2409,7 @@ static void __fork_processing(request_h request) {
 
 static int __launch_request_do(request_h request) {
   if (request->loader_id == PAD_LOADER_ID_DIRECT || request->cpc == nullptr ||
-      __asan_app_checker.CheckAsanApp(request->menu_info->appid)) {
+      launchpad::Debug::GetInst().CheckAsanApp(request->menu_info->appid)) {
     __fork_processing(request);
     return 0;
   }
@@ -3368,6 +3267,8 @@ static int __before_loop(int argc, char** argv) {
   launchpad::LauncherInfoInflator inflator;
   launcher_info_list = inflator.Inflate(LAUNCHER_INFO_PATH);
 
+  launchpad::Debug::GetInst().Init();
+
   __add_app_defined_loaders();
 
   ret = _send_cmd_to_amd(LAUNCHPAD_LAUNCH_SIGNAL);
@@ -3400,7 +3301,7 @@ static void __after_loop(void) {
   if (_send_cmd_to_amd(LAUNCHPAD_DEAD_SIGNAL) < 0)
     _W("Failed to send cmd(%d) to amd", LAUNCHPAD_DEAD_SIGNAL);
 
-  _debug_fini();
+  launchpad::Debug::GetInst().Dispose();
   launcher_info_list.clear();
   _config_fini();
   _inotify_fini();
diff --git a/src/launchpad-process-pool/launchpad_debug.cc b/src/launchpad-process-pool/launchpad_debug.cc
deleted file mode 100644 (file)
index d94c194..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "launchpad-process-pool/launchpad_debug.h"
-
-#include <bundle_internal.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <linux/limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <algorithm>
-
-#include "launchpad-process-pool/debugger_info.hh"
-#include "lib/common/inc/key.h"
-#include "lib/common/inc/launchpad_common.h"
-#include "lib/common/inc/launchpad_types.h"
-
-#define DEBUGGER_INFO_PATH "/usr/share/aul"
-
-namespace {
-
-int __debug_initialized;
-std::vector<launchpad::DebuggerInfoPtr> __debugger_info_list;
-launchpad::DebuggerInfoPtr __debugger_info;
-std::vector<std::string> __debug_argv_list;
-std::vector<std::string> __extra_argv_list;
-
-}  // namespace
-
-int _debug_change_mount_namespace(void) {
-  const char* pid_str;
-  char buf[PATH_MAX];
-  int ret;
-  int fd;
-
-  pid_str = getenv("TARGET_PID");
-  if (pid_str == nullptr)
-    return 0;
-
-  snprintf(buf, sizeof(buf), "/proc/%s/ns/mnt", pid_str);
-  fd = open(buf, O_RDONLY);
-  if (fd < 0) {
-    _E("open() is failed. path(%s), errno(%d)", buf, errno);
-    return -1;
-  }
-
-  ret = setns(fd, CLONE_NEWNS);
-  close(fd);
-  if (ret != 0)
-    _E("setns() is failed. errno(%d)", errno);
-
-  return ret;
-}
-
-int _debug_create_extra_argv(int* argc, char*** argv) {
-  int new_argc;
-  char** new_argv;
-  int i;
-
-  if (argc == nullptr || argv == nullptr) {
-    _E("[DEBUG] Invalid parameter");
-    return -1;
-  }
-
-  if (__debugger_info == nullptr)
-    return 0;
-
-  new_argc = __extra_argv_list.size();
-  if (new_argc == 0)
-    return 0;
-
-  new_argv = static_cast<char**>(calloc(new_argc, sizeof(char*)));
-  if (new_argv == nullptr) {
-    _E("out of memory");
-    return -1;
-  }
-
-  i = LOADER_ARG_PATH;
-  for (auto& argv : __extra_argv_list) {
-    new_argv[i++] = strdup(argv.c_str());
-  }
-
-  *argc = new_argc;
-  *argv = new_argv;
-  _D("[DEBUG] argc: %d, i: %d", *argc, i);
-
-  return 0;
-}
-
-int _debug_create_argv(int* argc, char*** argv, bool* attach) {
-  int new_argc = 0;
-  char** new_argv;
-  const char* exe;
-  const char* attach_str;
-  int i;
-
-  if (argc == nullptr || argv == nullptr || attach == nullptr) {
-    _E("[DEBUG] Invalid parameter");
-    return -1;
-  }
-
-  if (__debugger_info == nullptr)
-    return 0;
-
-  exe = __debugger_info->GetExe().data();
-  if (exe == nullptr)
-    return 0;
-
-  attach_str = __debugger_info->GetAttachInfo().c_str();
-  if (attach_str && strcasecmp(attach_str, "true") == 0) {
-    *attach = true;
-    new_argc++;
-  }
-
-  auto list = __debugger_info->GetDefaultOptList();
-  new_argc += __debug_argv_list.size() + list.size() + 1;
-  new_argv = static_cast<char**>(calloc(new_argc, sizeof(char*)));
-  if (new_argv == nullptr) {
-    _E("out of memory");
-    return -1;
-  }
-
-  i = LOADER_ARG_PATH;
-  new_argv[i++] = strdup(exe);
-
-  for (auto& debug_argv : list) {
-    new_argv[i++] = strdup(debug_argv.c_str());
-  }
-
-  for (auto& debug_argv : __debug_argv_list) {
-    new_argv[i++] = strdup(debug_argv.c_str());
-  }
-
-  *argc = new_argc;
-  *argv = new_argv;
-  _D("[DEBUG] argc: %d, argv[0]: %s", new_argc, new_argv[LOADER_ARG_PATH]);
-
-  return 0;
-}
-
-void _debug_destroy_argv(int argc, char** argv) {
-  int i;
-
-  if (argv == nullptr)
-    return;
-
-  for (i = 0; i < argc; i++)
-    free(argv[i]);
-  free(argv);
-}
-
-int _debug_get_caller_pid(bundle* kb) {
-  const char* pid_str;
-  int pid;
-
-  pid_str = bundle_get_val(kb, AUL_K_ORG_CALLER_PID);
-  if (pid_str == nullptr)
-    pid_str = bundle_get_val(kb, AUL_K_CALLER_PID);
-
-  if (pid_str == nullptr)
-    return -1;
-
-  pid = atoi(pid_str);
-  if (pid <= 1)
-    return -1;
-
-  return pid;
-}
-
-static int __redirect_std_fds(bundle* kb) {
-  char path[PATH_MAX];
-  char err_buf[1024];
-  int fd;
-  int caller_pid;
-
-  if (kb == nullptr) {
-    _E("[DEBUG] Invalid parameter");
-    return -1;
-  }
-
-  caller_pid = _debug_get_caller_pid(kb);
-  if (caller_pid < 0) {
-    _E("[DEBUG] Failed to get caller pid");
-    return -1;
-  }
-
-  /* stdin */
-  snprintf(path, sizeof(path), "/proc/%d/fd/0", caller_pid);
-  fd = open(path, O_RDONLY);
-  if (fd < 0) {
-    _E("[DEBUG] Failed to open %s [%s]", path,
-       strerror_r(errno, err_buf, sizeof(err_buf)));
-    return -1;
-  }
-  dup2(fd, 0);
-  close(fd);
-
-  /* stdout */
-  snprintf(path, sizeof(path), "/proc/%d/fd/1", caller_pid);
-  fd = open(path, O_WRONLY);
-  if (fd < 0) {
-    _E("[DEBUG] Failed to open %s [%s]", path,
-       strerror_r(errno, err_buf, sizeof(err_buf)));
-    return -1;
-  }
-  dup2(fd, 1);
-  close(fd);
-
-  /* stderr */
-  snprintf(path, sizeof(path), "/proc/%d/fd/2", caller_pid);
-  fd = open(path, O_WRONLY);
-  if (fd < 0) {
-    _E("[DEBUG] Failed to open %s [%s]", path,
-       strerror_r(errno, err_buf, sizeof(err_buf)));
-    return -1;
-  }
-  dup2(fd, 2);
-  close(fd);
-
-  return 0;
-}
-
-static void __add_extra_argv(const std::string& key, bundle* kb) {
-  const char* str;
-  const char** str_arr = nullptr;
-  int len = 0;
-  int i;
-
-  _D("[DEBUG] key: %s", key.c_str());
-  if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
-    str_arr = bundle_get_str_array(kb, key.c_str(), &len);
-  } else {
-    str = bundle_get_val(kb, key.c_str());
-    if (str) {
-      str_arr = &str;
-      len = 1;
-    }
-  }
-
-  for (i = 0; i < len; i++) {
-    if (str_arr[i] == nullptr)
-      break;
-
-    __extra_argv_list.push_back(str_arr[i]);
-  }
-
-  if (str_arr)
-    bundle_del(kb, key.c_str());
-}
-
-static void __add_debug_argv(const std::string& key, bundle* kb) {
-  const char* str;
-  const char** str_arr = nullptr;
-  int len = 0;
-  int i;
-
-  _D("[DEBUG] key: %s", key.c_str());
-  if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
-    str_arr = bundle_get_str_array(kb, key.c_str(), &len);
-  } else {
-    str = bundle_get_val(kb, key.c_str());
-    if (str) {
-      str_arr = &str;
-      len = 1;
-    }
-  }
-
-  for (i = 0; i < len; i++) {
-    if (str_arr[i] == nullptr)
-      break;
-
-    __debug_argv_list.push_back(str_arr[i]);
-    if (!strcmp(key.c_str(), "__DLP_ATTACH_ARG__")) {
-      if (isdigit(str_arr[i][0])) {
-        _D("Target PID: %s", str_arr[i]);
-        setenv("TARGET_PID", str_arr[i], 1);
-      }
-    }
-  }
-
-  if (str_arr)
-    bundle_del(kb, key.c_str());
-}
-
-static void __set_debug_env(const std::string& key, bundle* kb) {
-  const char* str;
-  const char** str_arr = nullptr;
-  int len = 0;
-  int i;
-  char buf[LINE_MAX] = {
-      0,
-  };
-
-  _D("[DEBUG] key: %s", key.c_str());
-  if (bundle_get_type(kb, key.c_str()) & BUNDLE_TYPE_ARRAY) {
-    str_arr = bundle_get_str_array(kb, key.c_str(), &len);
-  } else {
-    str = bundle_get_val(kb, key.c_str());
-    if (str) {
-      str_arr = &str;
-      len = 1;
-    }
-  }
-
-  if (str_arr == nullptr)
-    return;
-
-  strncat(buf, str_arr[0], sizeof(buf) - strlen(buf) - 1);
-  for (i = 1; i < len; i++) {
-    if (str_arr[i] == nullptr)
-      break;
-
-    strncat(buf, ",", sizeof(buf) - strlen(buf) - 1);
-    strncat(buf, str_arr[i], sizeof(buf) - strlen(buf) - 1);
-  }
-
-  bundle_del(kb, key.c_str());
-  _D("[DEBUG] name: %s, value: %s", key.c_str(), buf);
-  setenv(key.c_str(), buf, 1);
-}
-
-static void __remove_file(const std::string& file) {
-  _D("[DEBUG] file: %s", file.c_str());
-  if (access(file.c_str(), F_OK) == 0) {
-    if (remove(file.c_str()) != 0)
-      _W("[DEBUG] Failed to remove %s", file.c_str());
-  }
-}
-
-void _debug_prepare_debugger(bundle* kb) {
-  const char* debugger;
-  int ret;
-
-  if (kb == nullptr)
-    return;
-
-  debugger = bundle_get_val(kb, AUL_K_SDK);
-  if (debugger == nullptr)
-    return;
-
-  if (!strcmp(debugger, "ASAN"))
-    setenv("TIZEN_ASAN_ACTIVATION", "1", 1);
-
-  ret = __redirect_std_fds(kb);
-  if (ret < 0)
-    _E("[DEBUG] Failed to redirect standard fds");
-
-  _D("[DEBUG] debugger: %s", debugger);
-  auto it =
-      std::find_if(__debugger_info_list.begin(), __debugger_info_list.end(),
-                   [&](const launchpad::DebuggerInfoPtr& info) -> bool {
-                     return strcasecmp(info->GetExe().c_str(), debugger) == 0;
-                   });
-  if (it == __debugger_info_list.end())
-    return;
-
-  __debugger_info = *it;
-  for (auto& unlink_file : __debugger_info->GetUnlinkList()) {
-    __remove_file(unlink_file);
-  }
-
-  for (auto& extra_env : __debugger_info->GetExtraEnvList()) {
-    __set_debug_env(extra_env, kb);
-  }
-
-  for (auto& extra_key : __debugger_info->GetExtraKeyList()) {
-    __add_debug_argv(extra_key, kb);
-  }
-
-  for (auto& last_extra_key : __debugger_info->GetLastExtraKeyList()) {
-    __add_extra_argv(last_extra_key, kb);
-  }
-}
-
-int _debug_init(void) {
-  if (__debug_initialized)
-    return 0;
-
-  launchpad::DebuggerInfoInflator inflator;
-  __debugger_info_list = inflator.Inflate(DEBUGGER_INFO_PATH);
-  if (__debugger_info_list.empty())
-    return -1;
-
-  __debug_initialized = 1;
-
-  return 0;
-}
-
-void _debug_fini(void) {
-  if (!__debug_initialized)
-    return;
-
-  __debugger_info_list.clear();
-}
diff --git a/src/launchpad-process-pool/launchpad_debug.h b/src/launchpad-process-pool/launchpad_debug.h
deleted file mode 100644 (file)
index 7411ba1..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2016 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_DEBUG_H__
-#define __LAUNCHPAD_DEBUG_H__
-
-#include <stdbool.h>
-#include <bundle.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-int _debug_change_mount_namespace(void);
-int _debug_create_extra_argv(int *arg, char ***argv);
-int _debug_create_argv(int *argc, char ***argv, bool *attach);
-void _debug_destroy_argv(int argc, char **argv);
-int _debug_get_caller_pid(bundle *kb);
-void _debug_prepare_debugger(bundle *kb);
-int _debug_init(void);
-void _debug_fini(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LAUNCHPAD_DEBUG_H__ */
index 172d1bd..99fd9da 100644 (file)
  * limitations under the License.
  */
 
-#include "util.hh"
+#include "launchpad-process-pool/util.hh"
 
+#include <algorithm>
+#include <cctype>
 #include <regex>
+#include <utility>
 
 namespace launchpad {
 
 std::vector<std::string> Split(const std::string& str,
-                               const std::string& delim) {
+  const std::string& delim) {
   const std::regex deli("[^" + delim + "]+");
   std::vector<std::string> result;
   for (auto i = std::sregex_iterator(str.begin(), str.end(), deli);
-       i != std::sregex_iterator(); ++i) {
+       i != std::sregex_iterator(); ++i)
     result.push_back((*i).str());
-  }
 
   return result;
 }
 
+std::string ToUpper(std::string str) {
+  std::string result = std::move(str);
+  std::transform(result.begin(), result.end(), result.begin(), ::toupper);
+  return result;
+}
+
 }  // namespace launchpad
index 3fffdf0..b0f50e9 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef UTIL_HH_
-#define UTIL_HH_
+#ifndef LAUNCHPAD_PROCESS_POOL_UTIL_HH_
+#define LAUNCHPAD_PROCESS_POOL_UTIL_HH_
 
 #include <string>
 #include <vector>
@@ -33,8 +33,10 @@ bool operator==(E a, int x) {
 }
 
 std::vector<std::string> Split(const std::string& str,
-                               const std::string& delim);
+  const std::string& delim);
+
+std::string ToUpper(std::string str);
 
 }  // namespace launchpad
 
-#endif  // UTIL_HH_
+#endif  // LAUNCHPAD_PROCESS_POOL_UTIL_HH_
index 10086da..61279ef 100644 (file)
@@ -130,9 +130,9 @@ class LaunchpadTest : public ::testing::Test {
 
 TEST_F(LaunchpadTest, DebuggerInfoTest) {
   DebuggerInfoInflator inflator;
-  auto list = inflator.Inflate(".");
-  EXPECT_EQ(list.size(), 1);
-  auto info = std::move(list.front());
+  auto map = inflator.Inflate(".");
+  EXPECT_EQ(map.size(), 1);
+  auto info = std::move(map["DEBUG"]);
   EXPECT_EQ(info->GetName(), "DEBUG");
   EXPECT_EQ(info->GetExe(), "test_debugger");
   EXPECT_EQ(info->GetAppTypes().size(), 2);