Add memory management feature on app-defined-loader 21/225821/5
authorHwankyu Jhun <h.jhun@samsung.com>
Tue, 25 Feb 2020 00:43:15 +0000 (09:43 +0900)
committerHwankyu Jhun <h.jhun@samsung.com>
Tue, 25 Feb 2020 01:39:06 +0000 (10:39 +0900)
If PSS of app-defined-loader process is over the threshold,
app-defined-loader process stops loading the libraries.
The platform developer can change the threshold using
app-defined-loader.conf file.

Change-Id: Id2476dbcfbce5d3c272028a883ec6a509cfa310f
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
packaging/launchpad.spec
src/CMakeLists.txt
src/app-defined-loader/CMakeLists.txt [moved from src/app_defined_loader/CMakeLists.txt with 89% similarity]
src/app-defined-loader/conf/app-defined-loader.conf.in [new file with mode: 0644]
src/app-defined-loader/src/app-defined-loader.cc [moved from src/app_defined_loader/src/app_defined_loader.cc with 79% similarity]
src/app-defined-loader/src/config.cc [new file with mode: 0644]
src/app-defined-loader/src/config.hh [new file with mode: 0644]
src/app-defined-loader/src/log-private.hh [new file with mode: 0644]
src/app-defined-loader/src/proc.cc [new file with mode: 0644]
src/app-defined-loader/src/proc.hh [new file with mode: 0644]

index 5935833..581b221 100644 (file)
@@ -172,6 +172,7 @@ ln -sf ../launchpad-process-pool.service %{buildroot}%{_unitdir_user}/basic.targ
 %files -n app-defined-loader
 %manifest app-defined-loader.manifest
 %license LICENSE
+%{_prefix}/share/aul/app-defined-loader.conf
 %{_bindir}/app-defined-loader
 
 %files -n liblaunchpad
index dbab7f3..352038e 100644 (file)
@@ -3,7 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 ADD_SUBDIRECTORY(launchpad)
 ADD_SUBDIRECTORY(lib)
 ADD_SUBDIRECTORY(loader)
-ADD_SUBDIRECTORY(app_defined_loader)
+ADD_SUBDIRECTORY(app-defined-loader)
 ADD_SUBDIRECTORY(hydra)
 ADD_SUBDIRECTORY(parser)
 
similarity index 89%
rename from src/app_defined_loader/CMakeLists.txt
rename to src/app-defined-loader/CMakeLists.txt
index b0f869e..3410782 100644 (file)
@@ -4,13 +4,14 @@ SET(APP_DEFINED_LOADER "app-defined-loader")
 
 INCLUDE(FindPkgConfig)
 PKG_CHECK_MODULES(APP_DEFINED_LOADER_PKGS REQUIRED
+       aul
+       bundle
+       dbus-1
        dlog
        ecore
        ecore-core
-       bundle
-       aul
        gio-2.0
-       dbus-1
+       iniparser
        libsystemd
        )
 
@@ -66,4 +67,8 @@ SET_TARGET_PROPERTIES(${APP_DEFINED_LOADER} PROPERTIES COMPILE_FLAGS ${EXTRA_CFL
 SET_TARGET_PROPERTIES(${APP_DEFINED_LOADER}
        PROPERTIES SKIP_BUILD_RPATH TRUE
        ) # remove rpath option that is automatically generated by cmake.
-INSTALL(TARGETS ${APP_DEFINED_LOADER} DESTINATION bin)
\ No newline at end of file
+INSTALL(TARGETS ${APP_DEFINED_LOADER} DESTINATION bin)
+
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/conf/app-defined-loader.conf.in
+       ${CMAKE_CURRENT_SOURCE_DIR}/conf/app-defined-loader.conf @ONLY)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/conf/app-defined-loader.conf DESTINATION share/aul)
diff --git a/src/app-defined-loader/conf/app-defined-loader.conf.in b/src/app-defined-loader/conf/app-defined-loader.conf.in
new file mode 100644 (file)
index 0000000..8381685
--- /dev/null
@@ -0,0 +1,2 @@
+[Memory]
+Threshold=25600
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <linux/limits.h>
-#include <dlfcn.h>
 #include <Ecore.h>
 #include <bundle_internal.h>
+#include <dlfcn.h>
+#include <linux/limits.h>
+#include <stdint.h>
+#include <stdio.h>
 #include <sys/prctl.h>
 
 #include <bundle_cpp.h>
 #include <memory>
 #include <vector>
 
+#include "key.h"
+#include "launchpad.h"
 #include "launchpad_common.h"
 #include "launchpad_types.h"
-#include "launchpad.h"
-#include "key.h"
 
-#ifdef LOG_TAG
-#undef LOG_TAG
-#endif
-#define LOG_TAG "APP_DEFINED_LOADER"
+#include "config.hh"
+#include "log-private.hh"
+#include "proc.hh"
 
 #ifndef PR_TASK_PERF_USER_TRACE
 #define PR_TASK_PERF_USER_TRACE 666
 #define C_EXPORT extern "C" __attribute__((visibility("default")))
 #endif
 
-using namespace tizen_base;
-using namespace std;
 namespace launchpad {
 
+static const char PATH_CONF[] = "/usr/share/aul/app-defined-loader.conf";
+static const char SECTION_MEMORY[] = "Memory";
+static const char KEY_THRESHOLD[] = "Threshold";
+static uint32_t DEFAULT_THRESHOLD = 25600;  // kB
+
 class AppDefinedLoader {
  public:
   AppDefinedLoader(int argc, char** argv)
       : argc_(argc), argv_(argv) {
-    lifecycle_cb_ = shared_ptr<loader_lifecycle_callback_s>(new loader_lifecycle_callback_s());
+    lifecycle_cb_ = std::shared_ptr<loader_lifecycle_callback_s>(
+        new loader_lifecycle_callback_s());
     lifecycle_cb_->create = OnCreate;
     lifecycle_cb_->launch = OnLaunch;
     lifecycle_cb_->terminate = OnTerminate;
 
-    adapter_ = shared_ptr<loader_adapter_s>(new loader_adapter_s());
+    adapter_ = std::shared_ptr<loader_adapter_s>(new loader_adapter_s());
     adapter_->loop_begin = OnLoopBegin;
     adapter_->loop_quit = OnLoopQuit;
     adapter_->add_fd = OnAddFd;
     adapter_->remove_fd = OnRemoveFd;
+
+    proc_ = std::unique_ptr<Proc>(new Proc(getpid()));
+
+    Config conf(PATH_CONF);
+    int threshold = conf.GetIntValue(SECTION_MEMORY, KEY_THRESHOLD);
+    if (threshold > 0) {
+      threshold_ = static_cast<uint32_t>(threshold);
+    } else {
+      _W("Failed to get threshold");
+    }
   }
 
   ~AppDefinedLoader() {
     _W("app defined loader destroyed");
   }
 
-  shared_ptr<loader_lifecycle_callback_s> GetLifeCycle() {
+  std::shared_ptr<loader_lifecycle_callback_s> GetLifeCycle() {
     return lifecycle_cb_;
   }
 
-  shared_ptr<loader_adapter_s> GetAdapter() {
+  std::shared_ptr<loader_adapter_s> GetAdapter() {
     return adapter_;
   }
 
@@ -109,10 +123,11 @@ class AppDefinedLoader {
   }
 
  private:
-  static void PreloadLib(Bundle data) {
-    vector<std::string> so_array = data.GetStringArray("preload");
+  void PreloadLib(tizen_base::Bundle data) {
+    std::vector<std::string> so_array = data.GetStringArray("preload");
     if (so_array.size() == 0)
       return;
+
     for (auto& i : so_array) {
       if (i.empty())
         continue;
@@ -121,14 +136,20 @@ class AppDefinedLoader {
         _E("fail to load : %s, err : %s", i.c_str(), dlerror());
       else
         _D("preload %s# - handle : %p", i.c_str(), handle);
+
+      uint32_t pss = proc_->GetPss();
+      if (pss > threshold_) {
+        _W("Pss(%u) is over threshold(%u)", pss, threshold_);
+        break;
+      }
     }
   }
 
   static void OnCreate(bundle *extra, int type, void *user_data) {
     _I("on create");
     AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
-    Bundle ex = Bundle(extra, false, false);
-    string loader_type = ex.GetString(KEY_LOADER_TYPE);
+    tizen_base::Bundle ex = tizen_base::Bundle(extra, false, false);
+    std::string loader_type = ex.GetString(KEY_LOADER_TYPE);
     if (loader_type.empty()) {
       _E("No loader type");
       return;
@@ -147,7 +168,8 @@ class AppDefinedLoader {
   }
 
   static int OnLaunch(int argc, char **argv, const char *app_path,
-      const char *appid, const char *pkgid, const char *pkg_type, void *user_data) {
+      const char *appid, const char *pkgid, const char *pkg_type,
+      void *user_data) {
     _I("on launch");
     AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
     if (!loader->IsPriorityChangeEnabled())
@@ -157,19 +179,20 @@ class AppDefinedLoader {
     if (kb == nullptr)
       return 0;
 
-    Bundle data(kb, false, false);
-    string high_priority = data.GetString(AUL_K_HIGHPRIORITY);
+    tizen_base::Bundle data(kb, false, false);
+    std::string high_priority = data.GetString(AUL_K_HIGHPRIORITY);
     if (high_priority == "true")
       launchpad_loader_set_priority(-12);
     data.Delete(AUL_K_HIGHPRIORITY);
     return 0;
   }
 
-  void DoExec(string libdir) {
+  void DoExec(std::string libdir) {
     _I("do exec");
     char err_str[MAX_LOCAL_BUFSZ];
     if (access(argv_[LOADER_ARG_PATH], F_OK | R_OK)) {
-      SECURE_LOGE("access() failed for file: \"%s\", error: %d (%s)", argv_[LOADER_ARG_PATH], errno,
+      SECURE_LOGE("access() failed for file: \"%s\", error: %d (%s)",
+          argv_[LOADER_ARG_PATH], errno,
           strerror_r(errno, err_str, sizeof(err_str)));
     } else {
       SECURE_LOGD("[candidate] Exec application (%s)",
@@ -187,9 +210,10 @@ class AppDefinedLoader {
     }
   }
 
-  int DoDlOpen(bool restore, string old_cwd, string libdir) {
+  int DoDlOpen(bool restore, std::string old_cwd, std::string libdir) {
     _I("do dlopen");
-    string hwc_message = "" + to_string(getpid()) + "|lib loading start";
+    std::string hwc_message = "" + std::to_string(getpid()) +
+        "|lib loading start";
     prctl(PR_TASK_PERF_USER_TRACE, hwc_message.c_str(), hwc_message.size());
     void* handle = dlopen(argv_[LOADER_ARG_PATH],
         RTLD_LAZY | RTLD_GLOBAL | RTLD_NODELETE);
@@ -199,7 +223,7 @@ class AppDefinedLoader {
       return -1;
     }
 
-    hwc_message = "" + to_string(getpid()) + "|lib loading end";
+    hwc_message = "" + std::to_string(getpid()) + "|lib loading end";
     prctl(PR_TASK_PERF_USER_TRACE, hwc_message.c_str(), hwc_message.size());
 
     if (restore && chdir(old_cwd.c_str()))
@@ -218,7 +242,8 @@ class AppDefinedLoader {
   }
 
   static int OnTerminate(int argc, char **argv, void *user_data) {
-    SECURE_LOGD("[candidate] Launch real application (%s)", argv[LOADER_ARG_PATH]);
+    SECURE_LOGD("[candidate] Launch real application (%s)",
+        argv[LOADER_ARG_PATH]);
     char old_cwd[PATH_MAX] = {0, };
     AppDefinedLoader* loader = (AppDefinedLoader*)user_data;
     if (getcwd(old_cwd, sizeof(old_cwd)) == nullptr) {
@@ -237,7 +262,7 @@ class AppDefinedLoader {
           _E("failed to chdir: %d", errno);
         else
           restore = true;
-        string libdir_str = string(libdir);
+        std::string libdir_str = std::string(libdir);
         free(libdir);
         return loader->DoDlOpen(restore, old_cwd, libdir_str);
       }
@@ -302,20 +327,21 @@ class AppDefinedLoader {
   }
 
  private:
-  shared_ptr<loader_lifecycle_callback_s> lifecycle_cb_ = nullptr;
-  shared_ptr<loader_adapter_s> adapter_ = nullptr;
+  std::shared_ptr<loader_lifecycle_callback_s> lifecycle_cb_ = nullptr;
+  std::shared_ptr<loader_adapter_s> adapter_ = nullptr;
   bool loader_priority_enabled_ = false;
   bool priority_change_enabled_ = false;
-  loader_receiver_cb receiver_cb_;
+  loader_receiver_cb receiver_cb_ = nullptr;
   Ecore_Fd_Handler* fd_handler_ = nullptr;
+  std::unique_ptr<Proc> proc_;
+  uint32_t threshold_ = DEFAULT_THRESHOLD;
   int argc_;
   char** argv_;
 };
 
 }
 
-C_EXPORT int main(int argc, char **argv)
-{
+C_EXPORT int main(int argc, char **argv) {
   launchpad::AppDefinedLoader loader(argc, argv);
 
 #ifdef TIZEN_FEATURE_LOADER_PRIORITY
@@ -327,4 +353,4 @@ C_EXPORT int main(int argc, char **argv)
 
   return launchpad_loader_main(argc, argv,
       loader.GetLifeCycle().get(), loader.GetAdapter().get(), &loader);
-}
\ No newline at end of file
+}
diff --git a/src/app-defined-loader/src/config.cc b/src/app-defined-loader/src/config.cc
new file mode 100644 (file)
index 0000000..2a03202
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2020 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 <climits>
+
+#include "config.hh"
+
+namespace launchpad {
+
+Config::Config(const std::string& path)
+  : d_(iniparser_load(path.c_str()), iniparser_freedict) {
+}
+
+Config::~Config() = default;
+
+int Config::GetIntValue(const std::string& section,
+    const std::string& key) const {
+  std::string section_key = section + ":" + key;
+
+  return iniparser_getint(d_.get(), section_key.c_str(), INT_MIN);
+}
+
+}  // namespace launchpad
diff --git a/src/app-defined-loader/src/config.hh b/src/app-defined-loader/src/config.hh
new file mode 100644 (file)
index 0000000..3e12bdf
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2020 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 CONFIG_HH_
+#define CONFIG_HH_
+
+#include <iniparser.h>
+
+#include <memory>
+
+namespace launchpad {
+
+class Config {
+ public:
+  Config(const std::string& path);
+  virtual ~Config();
+
+ public:
+  int GetIntValue(const std::string& section, const std::string& key) const;
+
+ private:
+  std::unique_ptr<dictionary, decltype(iniparser_freedict)*> d_;
+};
+
+}  // namespace launchpad
+
+#endif  // CONFIG_HH_
diff --git a/src/app-defined-loader/src/log-private.hh b/src/app-defined-loader/src/log-private.hh
new file mode 100644 (file)
index 0000000..ee448ce
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2020 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 LOG_PRIVATE_HH_
+#define LOG_PRIVATE_HH_
+
+#include <dlog.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "APP_DEFINED_LOADER"
+
+#ifdef _E
+#undef _E
+#endif
+#define _E LOGE
+
+#ifdef _W
+#undef _W
+#endif
+#define _W LOGW
+
+#ifdef _I
+#undef _I
+#endif
+#define _I LOGI
+
+#ifdef _D
+#undef _D
+#endif
+#define _D LOGD
+
+#endif  // LOG_PRIVATE_HH_
diff --git a/src/app-defined-loader/src/proc.cc b/src/app-defined-loader/src/proc.cc
new file mode 100644 (file)
index 0000000..9719cea
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2020 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 <cstdio>
+#include <fstream>
+
+#include "log-private.hh"
+#include "proc.hh"
+
+namespace launchpad {
+
+Proc::Proc(int pid) : pid_(pid) {
+}
+
+Proc::~Proc() = default;
+
+uint32_t Proc::GetPss() const {
+  uint32_t total_pss = 0;
+  std::string path = "/proc/" + std::to_string(pid_) + "/smaps";
+  std::ifstream stream(path);
+  if (stream.is_open()) {
+    std::string line;
+    while (std::getline(stream, line)) {
+      uint32_t pss = 0;
+      if (std::sscanf(line.c_str(), "Pss: %u kB", &pss) == 1) {
+        total_pss += pss;
+        pss = 0;
+      }
+    }
+    stream.close();
+  }
+
+  _I("Pss: %u kB", total_pss);
+  return total_pss;
+}
+
+}  // namespace launchpad
diff --git a/src/app-defined-loader/src/proc.hh b/src/app-defined-loader/src/proc.hh
new file mode 100644 (file)
index 0000000..4ffb1a5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020 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 PROC_HH_
+#define PROC_HH_
+
+#include <stdint.h>
+
+namespace launchpad {
+
+class Proc {
+ public:
+  Proc(int pid);
+  virtual ~Proc();
+
+  uint32_t GetPss() const;
+
+ private:
+  int pid_;
+};
+
+}  // namespace launchpad
+
+#endif  // PROC_HH_