Implement configurations on limiter.conf 93/273093/1
authorUnsung Lee <unsung.lee@samsung.com>
Tue, 22 Mar 2022 05:44:41 +0000 (14:44 +0900)
committerUnsung Lee <unsung.lee@samsung.com>
Tue, 22 Mar 2022 06:29:13 +0000 (15:29 +0900)
Change-Id: I590d078f751869d75e75ae0359b67b4d284bb5b5
Signed-off-by: Unsung Lee <unsung.lee@samsung.com>
12 files changed:
; [new file with mode: 0644]
conf/limiter.conf
src/common/cgroup/cpu-cgroup.c
src/common/cgroup/memory-cgroup.c
src/common/cgroup/memory-cgroup.h
src/common/config-parser.c
src/common/module.c
src/common/util.h
src/resource-limiter/cpu/cpu-sched.c
src/resource-limiter/memory/lowmem-handler.h
src/resource-limiter/memory/lowmem-limit.c
src/resource-limiter/memory/vmpressure-lowmem-handler.c

diff --git a/; b/;
new file mode 100644 (file)
index 0000000..86abdd8
--- /dev/null
+++ b/;
@@ -0,0 +1,2343 @@
+/*
+ * resourced
+ *
+ * Copyright (c) 2012 - 2019 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.
+ */
+
+/*
+ * @file vmpressure-lowmem-handler.c
+ *
+ * @desc lowmem handler using memcgroup
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <limits.h>
+#include <vconf.h>
+#include <unistd.h>
+#include <time.h>
+#include <limits.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/shm.h>
+#include <sys/sysinfo.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <ctype.h>
+#include <bundle.h>
+#include <eventsystem.h>
+#include <malloc.h>
+
+#include "trace.h"
+#include "cgroup.h"
+#include "lowmem-handler.h"
+#include "proc-common.h"
+#include "procfs.h"
+#include "freezer.h"
+#include "resourced.h"
+#include "macro.h"
+#include "notifier.h"
+#include "config-parser.h"
+#include "module.h"
+#include "swap-common.h"
+#include "cgroup.h"
+#include "memory-cgroup.h"
+#include "heart-common.h"
+#include "proc-main.h"
+#include "dbus-handler.h"
+#include "util.h"
+#include "fd-handler.h"
+#include "resourced-helper-worker.h"
+#include "safe-kill.h"
+#include "dedup-common.h"
+
+#define LOWMEM_THRES_INIT              0
+
+#define MEMPS_EXEC_PATH                        "usr/bin/memps"
+#define MEM_CONF_FILE                   RD_CONFIG_FILE(limiter)
+#define MEM_SECTION             "Memory"
+#define MEM_VIP_SECTION                        "VIP_PROCESS"
+#define MEM_VIP_PREDEFINE              "PREDEFINE"
+#define MEM_POPUP_SECTION              "POPUP"
+#define MEM_POPUP_STRING               "oom_popup"
+#define MEM_BG_RECLAIM_SECTION "BackgroundReclaim"
+#define MEM_BG_RECLAIM_STRING  "AfterScreenDim"
+#define MEM_LOGGING_SECTION            "Logging"
+
+#define BUF_MAX                                1024
+#define MAX_VICTIMS_BETWEEN_CHECK      3
+#define MAX_PROACTIVE_LOW_VICTIMS      2
+#define MAX_PROACTIVE_HIGH_VICTIMS     4
+#define FOREGROUND_VICTIMS             1
+#define OOM_TIMER_INTERVAL             2
+#define OOM_KILLER_PRIORITY            -20
+#define THRESHOLD_MARGIN               10 /* MB */
+
+#define MEM_SIZE_64                    64  /* MB */
+#define MEM_SIZE_256                   256 /* MB */
+#define MEM_SIZE_448                   448 /* MB */
+#define MEM_SIZE_512                   512 /* MB */
+#define MEM_SIZE_768                   768 /* MB */
+#define MEM_SIZE_1024                  1024 /* MB */
+#define MEM_SIZE_2048                  2048 /* MB */
+
+/* thresholds for 64M RAM*/
+#define PROACTIVE_64_THRES                     10 /* MB */
+#define PROACTIVE_64_LEAVE                     30 /* MB */
+#define CGROUP_ROOT_64_THRES_DEDUP             16 /* MB */
+#define CGROUP_ROOT_64_THRES_SWAP              15 /* MB */
+#define CGROUP_ROOT_64_THRES_LOW               8  /* MB */
+#define CGROUP_ROOT_64_THRES_MEDIUM            5  /* MB */
+#define CGROUP_ROOT_64_THRES_LEAVE             8  /* MB */
+#define CGROUP_ROOT_64_NUM_VICTIMS             1
+
+/* thresholds for 256M RAM */
+#define PROACTIVE_256_THRES                    50 /* MB */
+#define PROACTIVE_256_LEAVE                    80 /* MB */
+#define CGROUP_ROOT_256_THRES_DEDUP    60 /* MB */
+#define CGROUP_ROOT_256_THRES_SWAP             40 /* MB */
+#define CGROUP_ROOT_256_THRES_LOW              20 /* MB */
+#define CGROUP_ROOT_256_THRES_MEDIUM           10 /* MB */
+#define CGROUP_ROOT_256_THRES_LEAVE            20 /* MB */
+#define CGROUP_ROOT_256_NUM_VICTIMS            2
+
+/* threshold for 448M RAM */
+#define PROACTIVE_448_THRES                    80 /* MB */
+#define PROACTIVE_448_LEAVE                    100 /* MB */
+#define CGROUP_ROOT_448_THRES_DEDUP    120 /* MB */
+#define CGROUP_ROOT_448_THRES_SWAP             100 /* MB */
+#define CGROUP_ROOT_448_THRES_LOW              60  /* MB */
+#define CGROUP_ROOT_448_THRES_MEDIUM           50  /* MB */
+#define CGROUP_ROOT_448_THRES_LEAVE            70  /* MB */
+#define CGROUP_ROOT_448_NUM_VICTIMS            5
+
+/* threshold for 512M RAM */
+#define PROACTIVE_512_THRES                    100 /* MB */
+#define PROACTIVE_512_LEAVE                    80 /* MB */
+#define CGROUP_ROOT_512_THRES_DEDUP    140 /* MB */
+#define CGROUP_ROOT_512_THRES_SWAP             100 /* MB */
+#define CGROUP_ROOT_512_THRES_LOW              70  /* MB */
+#define CGROUP_ROOT_512_THRES_MEDIUM           60  /* MB */
+#define CGROUP_ROOT_512_THRES_LEAVE            80  /* MB */
+#define CGROUP_ROOT_512_NUM_VICTIMS            5
+
+/* threshold for 768 RAM */
+#define PROACTIVE_768_THRES                    100 /* MB */
+#define PROACTIVE_768_LEAVE                    130 /* MB */
+#define CGROUP_ROOT_768_THRES_DEDUP    180 /* MB */
+#define CGROUP_ROOT_768_THRES_SWAP             150 /* MB */
+#define CGROUP_ROOT_768_THRES_LOW              90  /* MB */
+#define CGROUP_ROOT_768_THRES_MEDIUM           80  /* MB */
+#define CGROUP_ROOT_768_THRES_LEAVE            100  /* MB */
+#define CGROUP_ROOT_768_NUM_VICTIMS            5
+
+/* threshold for more than 1024M RAM */
+#define PROACTIVE_1024_THRES                   230 /* MB */
+#define PROACTIVE_1024_LEAVE                   150 /* MB */
+#define CGROUP_ROOT_1024_THRES_DEDUP           400 /* MB */
+#define CGROUP_ROOT_1024_THRES_SWAP            300 /* MB */
+#define CGROUP_ROOT_1024_THRES_LOW             120 /* MB */
+#define CGROUP_ROOT_1024_THRES_MEDIUM          100 /* MB */
+#define CGROUP_ROOT_1024_THRES_LEAVE           150 /* MB */
+#define CGROUP_ROOT_1024_NUM_VICTIMS           5
+
+/* threshold for more than 2048M RAM */
+#define PROACTIVE_2048_THRES                   200 /* MB */
+#define PROACTIVE_2048_LEAVE                   500 /* MB */
+#define CGROUP_ROOT_2048_THRES_DEDUP           400 /* MB */
+#define CGROUP_ROOT_2048_THRES_SWAP            300 /* MB */
+#define CGROUP_ROOT_2048_THRES_LOW             200 /* MB */
+#define CGROUP_ROOT_2048_THRES_MEDIUM          160 /* MB */
+#define CGROUP_ROOT_2048_THRES_LEAVE           300 /* MB */
+#define CGROUP_ROOT_2048_NUM_VICTIMS           10
+
+/* threshold for more than 3072M RAM */
+#define PROACTIVE_3072_THRES                   300 /* MB */
+#define PROACTIVE_3072_LEAVE                   700 /* MB */
+#define CGROUP_ROOT_3072_THRES_DEDUP           600 /* MB */
+#define CGROUP_ROOT_3072_THRES_SWAP            500 /* MB */
+#define CGROUP_ROOT_3072_THRES_LOW             400 /* MB */
+#define CGROUP_ROOT_3072_THRES_MEDIUM          250 /* MB */
+#define CGROUP_ROOT_3072_THRES_LEAVE           500 /* MB */
+#define CGROUP_ROOT_3072_NUM_VICTIMS           10
+
+static unsigned proactive_threshold;
+static unsigned proactive_leave;
+static unsigned lmk_start_threshold;
+
+static char *event_level = MEMCG_DEFAULT_EVENT_LEVEL;
+
+/**
+ * Resourced Low Memory Killer
+ * NOTE: planned to be moved to a separate file.
+ */
+/*-------------------------------------------------*/
+#define OOM_TIMER_INTERVAL_SEC 2
+#define LMW_LOOP_WAIT_TIMEOUT_MSEC     OOM_TIMER_INTERVAL_SEC*(G_USEC_PER_SEC)
+#define LMW_RETRY_WAIT_TIMEOUT_MSEC    (G_USEC_PER_SEC)
+
+struct lowmem_control {
+       /*
+        * For each queued request the following properties
+        * are required with two exceptions:
+        *  - status is being set by LMK
+        *  - callback is optional
+        */
+       /* Processing flags*/
+       unsigned int flags;
+       /* Indictator for OOM score of targeted processes */
+       enum cgroup_type type;
+
+       /* Desired size to be restored - level to be reached (MB)*/
+       unsigned int size;
+       /* Max number of processes to be considered */
+       unsigned int count;
+       /* Memory reclaim status */
+       int status;
+       /*
+        * Optional - if set, will be triggered by LMK once the request
+        * is handled.
+        */
+       void (*callback) (struct lowmem_control *);
+};
+
+struct lowmem_worker {
+       pthread_t       worker_thread;
+       GAsyncQueue     *queue;
+       int             active;
+       int             running;
+};
+
+static struct lowmem_worker lmw;
+
+static int memlog_enabled;
+static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
+/* remove logfiles to reduce to this threshold.
+ * it is about five-sixths of the memlog_nr_max. */
+static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
+static char *memlog_path = DEFAULT_MEMLOG_PATH;
+static char *memlog_prefix[MEMLOG_MAX];
+
+#define LOWMEM_WORKER_IS_ACTIVE(_lmw)  g_atomic_int_get(&(_lmw)->active)
+#define LOWMEM_WORKER_ACTIVATE(_lmw)   g_atomic_int_set(&(_lmw)->active, 1)
+#define LOWMEM_WORKER_DEACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 0)
+
+#define LOWMEM_WORKER_IS_RUNNING(_lmw) g_atomic_int_get(&(_lmw)->running)
+#define LOWMEM_WORKER_RUN(_lmw)        g_atomic_int_set(&(_lmw)->running, 1)
+#define LOWMEM_WORKER_IDLE(_lmw)       g_atomic_int_set(&(_lmw)->running, 0)
+
+#define LOWMEM_NEW_REQUEST() g_slice_new0(struct lowmem_control)
+
+#define LOWMEM_DESTROY_REQUEST(_ctl)           \
+       g_slice_free(typeof(*(_ctl)), _ctl);    \
+
+#define LOWMEM_SET_REQUEST(c, __flags, __type, __size, __count, __cb)  \
+{                                                                      \
+       (c)->flags      = __flags; (c)->type    = __type;               \
+       (c)->size       = __size;  (c)->count   = __count;              \
+       (c)->callback   = __cb;                                         \
+}
+
+#define BUFF_MAX        255
+#define APP_ATTR_PATH "/proc/%d/attr/current"
+
+static int get_privilege(pid_t pid, char *name, size_t len)
+{
+       char path[PATH_MAX];
+       char attr[BUFF_MAX];
+       size_t attr_len;
+       FILE *fp;
+
+       snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
+
+       fp = fopen(path, "r");
+       if (!fp)
+               return -errno;
+
+       attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
+       fclose(fp);
+       if (attr_len <= 0)
+               return -ENOENT;
+
+       attr[attr_len] = '\0';
+
+       snprintf(name, len, "%s", attr);
+       return 0;
+}
+
+static int is_app(pid_t pid)
+{
+       char attr[BUFF_MAX];
+       size_t len;
+       int ret;
+
+       ret = get_privilege(pid, attr, sizeof(attr));
+       if (ret < 0) {
+               _E("Failed to get privilege of PID(%d).", pid);
+               return -1;
+       }
+
+       len = strlen(attr) + 1;
+
+       if (!strncmp("System", attr, len))
+               return 0;
+
+       if (!strncmp("User", attr, len))
+               return 0;
+
+       if (!strncmp("System::Privileged", attr, len))
+               return 0;
+
+       return 1;
+}
+
+
+static void lowmem_queue_request(struct lowmem_worker *lmw,
+                               struct lowmem_control *ctl)
+{
+       if (LOWMEM_WORKER_IS_ACTIVE(lmw))
+               g_async_queue_push(lmw->queue, ctl);
+}
+
+/* internal */
+static void lowmem_drain_queue(struct lowmem_worker *lmw)
+{
+       struct lowmem_control *ctl;
+
+       g_async_queue_lock(lmw->queue);
+       while ((ctl = g_async_queue_try_pop_unlocked(lmw->queue))) {
+               if (ctl->callback)
+                       ctl->callback(ctl);
+               LOWMEM_DESTROY_REQUEST(ctl);
+       }
+       g_async_queue_unlock(lmw->queue);
+}
+
+static void lowmem_request_destroy(gpointer data)
+{
+       struct lowmem_control *ctl = (struct lowmem_control*) data;
+
+       if (ctl->callback)
+               ctl->callback(ctl);
+       LOWMEM_DESTROY_REQUEST(ctl);
+}
+
+/*-------------------------------------------------*/
+
+/* low memory action function for cgroup */
+static void memory_cgroup_proactive_lmk_act(enum cgroup_type type, struct memcg_info *mi);
+/* low memory action function */
+static void high_mem_act(void);
+static void swap_activate_act(void);
+static void swap_compact_act(void);
+static void lmk_act(void);
+
+
+static size_t cur_mem_state = MEM_LEVEL_HIGH;
+static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
+static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
+
+static unsigned long totalram;
+static unsigned long ktotalram;
+
+static struct module_ops memory_modules_ops;
+static const struct module_ops *lowmem_ops;
+static bool oom_popup_enable;
+static bool oom_popup;
+static bool memcg_swap_status;
+static bool bg_reclaim;
+static int fragmentation_size;
+
+static const char *convert_cgroup_type_to_str(int type)
+{
+       static const char *type_table[] =
+       {"/", "VIP", "High", "Medium", "Lowest"};
+       if (type >= CGROUP_ROOT && type <= CGROUP_LOW)
+               return type_table[type];
+       else
+               return "Error";
+}
+
+static const char *convert_status_to_str(int status)
+{
+       static const char *status_table[] =
+       {"none", "done", "drop", "cont", "retry", "next_type"};
+       if(status >= LOWMEM_RECLAIM_NONE && status <= LOWMEM_RECLAIM_NEXT_TYPE)
+               return status_table[status];
+       return "error status";
+}
+
+static const char *convert_memstate_to_str(int mem_state)
+{
+       static const char *state_table[] = {"mem normal", "mem dedup", "mem swap", "mem low",
+                       "mem medium"};
+       if (mem_state >= 0 && mem_state < MEM_LEVEL_MAX)
+               return state_table[mem_state];
+       return "";
+}
+
+static int lowmem_launch_oompopup(void)
+{
+       GVariantBuilder *const gv_builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
+       g_variant_builder_add(gv_builder, "{ss}", "_SYSPOPUP_CONTENT_", "lowmemory_oom");
+
+       GVariant *const params = g_variant_new("(a{ss})", gv_builder);
+       g_variant_builder_unref(gv_builder);
+
+       int ret = d_bus_call_method_sync_gvariant(SYSTEM_POPUP_BUS_NAME,
+               SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
+               "PopupLaunch", params);
+
+       g_variant_unref(params);
+
+       return ret;
+}
+
+static inline void get_total_memory(void)
+{
+       struct sysinfo si;
+       if (totalram)
+               return;
+
+       if (!sysinfo(&si)) {
+               totalram = si.totalram;
+               ktotalram = BYTE_TO_KBYTE(totalram);
+       }
+}
+
+static int lowmem_mem_usage_uss(pid_t pid, unsigned int *usage)
+{
+       unsigned int uss, zram = 0;
+       int ret;
+
+       *usage = 0;
+
+       /*
+        * In lowmem we need to know memory size of processes to
+        * for terminating apps. To get most real value of usage
+        * we should use USS + ZRAM usage for selected process.
+        *
+        * Those values will contain the most approximated amount
+        * of memory that will be freed after process termination.
+        */
+       ret = proc_get_uss(pid, &uss);
+       if (ret != RESOURCED_ERROR_NONE)
+               return ret;
+
+       if (swap_get_state() == SWAP_ON) {
+               ret = proc_get_zram_usage(pid, &zram);
+               /* If we don't get zram usage, it's not a problem */
+               if (ret != RESOURCED_ERROR_NONE)
+                       zram = 0;
+       }
+       *usage = uss + zram;
+       return RESOURCED_ERROR_NONE;
+}
+
+unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
+{
+       unsigned int size = 0, total_size = 0;
+       int index, ret;
+       pid_t pid;
+
+       /*
+        * If pids are allocated only when there are multiple processes with
+        * the same pgid e.g., browser and web process. Mostly, single process
+        * is used.
+        */
+       if (tsk->pids == NULL) {
+               ret = proc_get_ram_usage(tsk->pid, &size);
+
+               /* If there is no proc entry for given pid the process
+                * should be abandoned during further processing
+                */
+               if (ret < 0)
+                       _D("failed to get rss memory usage of %d", tsk->pid);
+
+               return size;
+       }
+
+       for (index = 0; index < tsk->pids->len; index++) {
+               pid = g_array_index(tsk->pids, pid_t, index);
+               ret = proc_get_ram_usage(pid, &size);
+               if (ret != RESOURCED_ERROR_NONE)
+                       continue;
+               total_size += size;
+       }
+
+       return total_size;
+}
+
+static int memps_file_select(const struct dirent *entry)
+{
+       return strstr(entry->d_name, "memps") ? 1 : 0;
+}
+
+static char *strrstr(const char *str, const char *token)
+{
+       int len = strlen(token);
+       const char *p = str + strlen(str);
+
+       while (str <= --p)
+               if (p[0] == token[0] && strncmp(p, token, len) == 0)
+                       return (char *)p;
+
+       return NULL;
+}
+
+static int timesort(const struct dirent **a, const struct dirent **b)
+{
+       long long time1 = 0;
+       long long time2 = 0;
+       char *ptr;
+
+       ptr = strrstr((*a)->d_name, "_");
+       if (ptr && *++ptr)
+               time1 = atoll(ptr);
+
+       ptr = strrstr((*b)->d_name, "_");
+       if (ptr && *++ptr)
+               time2 = atoll(ptr);
+
+       return (time1 - time2);
+}
+
+static int clear_logs(void *data)
+{
+       struct dirent **namelist;
+       int n, i, ret;
+       char fpath[BUF_MAX];
+       char *fname;
+       char *dir = (char*)data;
+       int len;
+
+       if (!memlog_enabled)
+               return RESOURCED_ERROR_NONE;
+
+       if (!dir)
+               return RESOURCED_ERROR_NONE;
+
+       len = strlen(dir);
+       if (len <= 0 || len >= sizeof fpath - 1) {
+               _E("Invalid parameter - Directory path is too short or too long");
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+       }
+
+       n = scandir(dir, &namelist, memps_file_select, timesort);
+
+       _D("num of log files %d", n);
+       if (n <= memlog_nr_max) {
+               while (n--)
+                       free(namelist[n]);
+               free(namelist);
+               return RESOURCED_ERROR_NONE;
+       }
+
+       strncpy(fpath, dir, sizeof fpath - 1);
+       fpath[sizeof fpath - 1] = '\0';
+       fname = fpath + len;
+       *fname++ = '/';
+
+       len = sizeof fpath - len - 1;
+       for (i = 0; i < n; i++) {
+               if (i < n - memlog_remove_batch_thres) {
+                       if (strlen(namelist[i]->d_name) > len - 1)
+                               continue;
+                       strncpy(fname, namelist[i]->d_name, len - 1);
+                       fpath[sizeof fpath - 1] = '\0';
+                       _D("remove log file %s", fpath);
+                       ret = remove(fpath);
+                       if (ret < 0)
+                               _E("%s file cannot removed", fpath);
+               }
+
+               free(namelist[i]);
+       }
+       free(namelist);
+       return RESOURCED_ERROR_NONE;
+}
+
+void make_memps_log(enum mem_log memlog, pid_t pid, char *victim_name)
+{
+       time_t now;
+       struct tm cur_tm;
+       char new_log[BUF_MAX];
+       static pid_t old_pid;
+       int oom_score_adj = 0, ret;
+       char *prefix;
+
+       if (!memlog_enabled)
+               return;
+
+       if (memlog < MEMLOG_MEMPS || memlog >= MEMLOG_MAX)
+               return;
+
+       prefix = memlog_prefix[memlog];
+
+       if (old_pid == pid)
+               return;
+
+       old_pid = pid;
+
+       now = time(NULL);
+
+       if (localtime_r(&now, &cur_tm) == NULL) {
+               _E("Fail to get localtime");
+               return;
+       }
+
+       snprintf(new_log, sizeof(new_log),
+               "%s/%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", memlog_path, prefix, victim_name,
+               pid, (1900 + cur_tm.tm_year), 1 + cur_tm.tm_mon,
+               cur_tm.tm_mday, cur_tm.tm_hour, cur_tm.tm_min,
+               cur_tm.tm_sec);
+
+       ret = proc_get_oom_score_adj(pid, &oom_score_adj);
+       if (ret || oom_score_adj > OOMADJ_BACKGRD_LOCKED) {
+
+               _cleanup_fclose_ FILE *f = NULL;
+
+               f = fopen(new_log, "w");
+               if (!f) {
+                       _E("fail to create memps log %s", new_log);
+                       return;
+               }
+               proc_print_meninfo(f);
+
+       } else {
+
+               const char *argv[4] = {"/usr/bin/memps", "-f", NULL, NULL};
+
+               argv[2] = new_log;
+               exec_cmd(ARRAY_SIZE(argv), argv);
+       }
+
+       /* best effort to limit the number of logfiles up to memlog_nr_max */
+       clear_logs(memlog_path);
+}
+
+static int lowmem_kill_victim(const struct task_info *tsk,
+               int flags, int memps_log, unsigned int *victim_size)
+{
+       pid_t pid;
+       int ret;
+       char appname[PATH_MAX];
+       int sigterm = 0;
+       struct proc_app_info *pai;
+
+       pid = tsk->pid;
+
+       if (pid <= 0 || pid == getpid())
+               return RESOURCED_ERROR_FAIL;
+
+       ret = proc_get_cmdline(pid, appname, sizeof appname);
+       if (ret == RESOURCED_ERROR_FAIL)
+               return RESOURCED_ERROR_FAIL;
+
+       if (!strcmp("memps", appname) ||
+           !strcmp("crash-worker", appname) ||
+           !strcmp("system-syspopup", appname)) {
+               _E("%s(%d) was selected, skip it", appname, pid);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       if (!memps_log)
+               make_memps_log(MEMLOG_MEMPS, pid, appname);
+
+       pai = tsk->pai;
+       if (pai) {
+               resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
+                       pid, NULL, NULL, PROC_TYPE_NONE);
+
+               if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
+                       sigterm = 1;
+               } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
+                       int app_flag = pai->flags;
+                       sigterm = app_flag & PROC_SIGTERM;
+               }
+
+               if (pai->memory.oom_killed)
+                       sigterm = 0;
+
+               pai->memory.oom_killed = true;
+       }
+
+       if (sigterm)
+               safe_kill(pid, SIGTERM);
+       else
+               safe_kill(pid, SIGKILL);
+
+       _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u, sigterm = %d\n",
+          flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
+          tsk->size, sigterm);
+       *victim_size = tsk->size;
+
+       if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
+               return RESOURCED_ERROR_NONE;
+
+       if (oom_popup_enable && !oom_popup) {
+               lowmem_launch_oompopup();
+               oom_popup = true;
+       }
+       if (memps_log)
+               make_memps_log(MEMLOG_MEMPS, pid, appname);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+/* return LOWMEM_RECLAIM_CONT when killing should be continued */
+static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
+{
+       unsigned int available;
+
+       /*
+        * Processes with the priority higher than perceptible are killed
+        * only when the available memory is less than dynamic oom threshold.
+        */
+       if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
+               return LOWMEM_RECLAIM_CONT;
+
+       if (flags & (OOM_FORCE|OOM_SINGLE_SHOT)) {
+               _I("[LMK] %d is dropped during force kill, flag=%d",
+                       tsk->pid, flags);
+               return LOWMEM_RECLAIM_DROP;
+       }
+       available = proc_get_mem_available();
+       if (available > lmk_start_threshold) {
+               _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
+                       available, lmk_start_threshold);
+               return LOWMEM_RECLAIM_RETRY;
+       }
+       return LOWMEM_RECLAIM_CONT;
+}
+
+static int compare_victims(const struct task_info *ta, const struct task_info *tb)
+{
+        unsigned int pa, pb;
+
+       assert(ta != NULL);
+       assert(tb != NULL);
+       /*
+        * followed by kernel badness point calculation using heuristic.
+        * oom_score_adj is normalized by its unit, which varies -1000 ~ 1000.
+        */
+       pa = ta->oom_score_lru * (ktotalram / 2000) + ta->size;
+       pb = tb->oom_score_lru * (ktotalram / 2000) + tb->size;
+
+       return pb - pa;
+}
+
+static void lowmem_free_task_info_array(GArray *array)
+{
+       int i;
+
+       for (i = 0; i < array->len; i++) {
+               struct task_info *tsk;
+
+               tsk = &g_array_index(array, struct task_info, i);
+               if (tsk->pids)
+                       g_array_free(tsk->pids, true);
+       }
+
+       g_array_free(array, true);
+}
+
+static inline int is_dynamic_process_killer(int flags)
+{
+       return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK);
+}
+
+static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres)
+{
+       unsigned int available = proc_get_mem_available();
+       unsigned int should_be_freed = 0;
+
+       if (available < thres)
+               should_be_freed = thres - available;
+       /*
+        * free THRESHOLD_MARGIN more than real should be freed,
+        * because launching app is consuming up the memory.
+        */
+       if (should_be_freed > 0)
+               should_be_freed += THRESHOLD_MARGIN;
+
+       *avail = available;
+
+       return should_be_freed;
+}
+
+static int lowmem_get_pids_proc(GArray *pids)
+{
+       DIR *dp;
+       struct dirent *dentry;
+
+       dp = opendir("/proc");
+       if (!dp) {
+               _E("fail to open /proc");
+               return RESOURCED_ERROR_FAIL;
+       }
+       while ((dentry = readdir(dp)) != NULL) {
+               struct task_info tsk;
+               pid_t pid = 0, pgid = 0;
+               int oom = 0;
+
+               if (!isdigit(dentry->d_name[0]))
+                       continue;
+
+               pid = (pid_t)atoi(dentry->d_name);
+               if (pid < 1)
+                       /* skip invalid pids or kernel processes */
+                       continue;
+
+               pgid = getpgid(pid);
+               if (pgid < 1)
+                       continue;
+
+               if(is_app(pid) != 1)
+                       continue;
+
+               if (proc_get_oom_score_adj(pid, &oom) < 0) {
+                       _D("pid(%d) was already terminated", pid);
+                       continue;
+               }
+
+               /* VIP pids should be excluded from the LMK list */
+               if (cgroup_get_type(oom) == CGROUP_VIP)
+                       continue;
+
+               /*
+                * Check whether this array includes applications or not.
+                * If it doesn't require to get applications
+                * and pid has been already included in pai,
+                * skip to append.
+                */
+               if (oom > OOMADJ_SU && oom <= OOMADJ_APP_MAX)
+                       continue;
+
+               /*
+                * Currently, for tasks in the memory cgroup,
+                * do not consider multiple tasks with one pgid.
+                */
+               tsk.pid = pid;
+               tsk.pgid = pgid;
+               tsk.oom_score_adj = oom;
+               tsk.oom_score_lru = oom;
+               tsk.pids = NULL;
+               tsk.size = lowmem_get_task_mem_usage_rss(&tsk);
+               tsk.pai = NULL;
+
+               g_array_append_val(pids, tsk);
+       }
+
+       closedir(dp);
+       return RESOURCED_ERROR_NONE;
+}
+
+/**
+ * @brief Terminate up to max_victims processes after finding them from pai.
+       It depends on proc_app_info lists
+       and it also reference systemservice cgroup
+       because some processes in this group don't have proc_app_info.
+ *
+ * @max_victims:           max number of processes to be terminated
+ * @start_oom:     find victims from start oom adj score value
+ * @end_oom: find victims to end oom adj score value
+ * @should_be_freed: amount of memory to be reclaimed (in MB)
+ * @total_size[out]: total size of possibly reclaimed memory (required)
+ * @completed:     final outcome (optional)
+ * @threshold:         desired value of memory available
+ */
+static int lowmem_kill_victims(int max_victims,
+       int start_oom, int end_oom, unsigned should_be_freed, int flags,
+       unsigned int *total_size, int *completed, int threshold)
+{
+       int total_count = 0;
+       GSList *proc_app_list = NULL;
+       int i, ret, victim = 0;
+       unsigned int victim_size = 0;
+       unsigned int total_victim_size = 0;
+       int status = LOWMEM_RECLAIM_NONE;
+       GArray *candidates = NULL;
+       GSList *iter, *iterchild;
+       struct proc_app_info *pai = NULL;
+       int oom_score_adj;
+       int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
+
+       candidates = g_array_new(false, false, sizeof(struct task_info));
+
+       proc_app_list = proc_app_list_open();
+       gslist_for_each_item(iter, proc_app_list) {
+               struct task_info ti;
+
+               total_count++;
+               pai = (struct proc_app_info *)iter->data;
+               if (!pai->main_pid)
+                       continue;
+
+               oom_score_adj = pai->memory.oom_score_adj;
+               if (oom_score_adj > end_oom || oom_score_adj < start_oom)
+                       continue;
+
+               if ((flags & OOM_REVISE) && pai->memory.oom_killed)
+                       continue;
+
+               ti.pid = pai->main_pid;
+               ti.pgid = getpgid(ti.pid);
+               ti.oom_score_adj = oom_score_adj;
+               ti.pai = pai;
+
+               /*
+                * Before oom_score_adj of favourite (oom_score = 270) applications is
+                * independent of lru_state, now we consider lru_state, while
+                * killing favourite process.
+                */
+
+               if (oom_score_adj == OOMADJ_FAVORITE && pai->lru_state >= PROC_BACKGROUND)
+                       ti.oom_score_lru = OOMADJ_FAVORITE + OOMADJ_FAVORITE_APP_INCREASE * pai->lru_state;
+               else
+                       ti.oom_score_lru = oom_score_adj;
+
+               if (pai->childs) {
+                       ti.pids = g_array_new(false, false, sizeof(pid_t));
+                       g_array_append_val(ti.pids, ti.pid);
+                       gslist_for_each_item(iterchild, pai->childs) {
+                               pid_t child = GPOINTER_TO_PID(iterchild->data);
+                               g_array_append_val(ti.pids, child);
+                       }
+               } else
+                       ti.pids = NULL;
+
+               g_array_append_val(candidates, ti);
+       }
+
+       proc_app_list_close();
+
+       if (!candidates->len) {
+               status = LOWMEM_RECLAIM_NEXT_TYPE;
+               goto leave;
+       }
+       else {
+               _D("[LMK] candidate ratio=%d/%d", candidates->len, total_count);
+       }
+
+       for (i = 0; i < candidates->len; i++) {
+               struct task_info *tsk;
+
+               tsk = &g_array_index(candidates, struct task_info, i);
+               tsk->size = lowmem_get_task_mem_usage_rss(tsk);
+       }
+
+       /*
+        * In case of start_oom == OOMADJ_SU,
+        * we're going to try to kill some of processes in /proc
+        * to handle low memory situation.
+        * It can find malicious system process even though it has low oom score.
+        */
+       if (start_oom == OOMADJ_SU)
+               lowmem_get_pids_proc(candidates);
+
+       g_array_sort(candidates, (GCompareFunc)compare_victims);
+
+       for (i = 0; i < candidates->len; i++) {
+               struct task_info *tsk;
+
+               if (i >= max_victims) {
+                       status = LOWMEM_RECLAIM_NEXT_TYPE;
+                       break;
+               }
+
+               /*
+                * Available memory is checking only every
+                * num_vict_between_check process for reducing burden.
+                */
+               if (!(i % num_vict_between_check)) {
+                       if (proc_get_mem_available() > threshold) {
+                               status = LOWMEM_RECLAIM_DONE;
+                               break;
+                       }
+               }
+
+               if (!(flags & OOM_NOMEMORY_CHECK) &&
+                   total_victim_size >= should_be_freed_kb) {
+                       _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
+                               victim, max_victims, total_victim_size);
+                       status = LOWMEM_RECLAIM_DONE;
+                       break;
+               }
+
+               tsk = &g_array_index(candidates, struct task_info, i);
+
+               status = lowmem_check_kill_continued(tsk, flags);
+               if (status != LOWMEM_RECLAIM_CONT)
+                       break;
+
+               _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n", tsk->pid, tsk->oom_score_adj);
+
+               ret = lowmem_kill_victim(tsk, flags, i, &victim_size);
+               if (ret != RESOURCED_ERROR_NONE)
+                       continue;
+               victim++;
+               total_victim_size += victim_size;
+       }
+
+leave:
+       lowmem_free_task_info_array(candidates);
+       *total_size = total_victim_size;
+       if(*completed != LOWMEM_RECLAIM_CONT)
+               *completed = status;
+       else
+               *completed = LOWMEM_RECLAIM_NEXT_TYPE;
+       return victim;
+}
+
+static int calculate_range_of_oom(enum cgroup_type type, int *min, int *max)
+{
+       if (type == CGROUP_VIP || type >= CGROUP_END || type <= CGROUP_TOP) {
+               _E("cgroup type (%d) is out of scope", type);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       *max = cgroup_get_highest_oom_score_adj(type);
+       *min = cgroup_get_lowest_oom_score_adj(type);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void lowmem_handle_request(struct lowmem_control *ctl)
+{
+       int start_oom, end_oom;
+       int count = 0, victim_cnt = 0;
+       int max_victim_cnt = ctl->count;
+       int status = LOWMEM_RECLAIM_NONE;
+       unsigned int available = 0;
+       unsigned int total_size = 0;
+       unsigned int current_size = 0;
+       unsigned int reclaim_size, shortfall = 0;
+       enum cgroup_type cgroup_type = ctl->type;
+
+       available = proc_get_mem_available();
+       reclaim_size = ctl->size  > available
+                    ? ctl->size - available : 0;
+
+       if (!reclaim_size) {
+               status = LOWMEM_RECLAIM_DONE;
+               goto done;
+       }
+
+retry:
+       /* Prepare LMK to start doing it's job. Check preconditions. */
+       if (calculate_range_of_oom(cgroup_type, &start_oom, &end_oom))
+               goto done;
+
+       lmk_start_threshold = get_root_memcg_info()->threshold[MEM_LEVEL_OOM];
+       shortfall = is_memory_recovered(&available, ctl->size);
+
+       if (!shortfall || !reclaim_size) {
+               status = LOWMEM_RECLAIM_DONE;
+               goto done;
+       }
+
+       /* precaution */
+       current_size = 0;
+       victim_cnt = lowmem_kill_victims(max_victim_cnt, start_oom, end_oom,
+                           reclaim_size, ctl->flags, &current_size, &status, ctl->size);
+
+       if (victim_cnt) {
+               current_size = KBYTE_TO_MBYTE(current_size);
+               reclaim_size -= reclaim_size > current_size
+                       ? current_size : reclaim_size;
+               total_size += current_size;
+               count += victim_cnt;
+               _I("[LMK] current: kill %d victims, reclaim_size=%uMB from %d to %d status=%s",
+                               victim_cnt, current_size,
+                               start_oom, end_oom, convert_status_to_str(status));
+       }
+
+       if ((status == LOWMEM_RECLAIM_DONE) ||
+           (status == LOWMEM_RECLAIM_DROP) ||
+           (status == LOWMEM_RECLAIM_RETRY))
+               goto done;
+
+       /*
+        * If it doesn't finish reclaiming memory in first operation,
+               - if flags has OOM_IN_DEPTH,
+                  try to find victims again in the active cgroup.
+                  otherwise, just return because there is no more victims in the desired cgroup.
+               - if flags has OOM_REVISE,
+                  it means that resourced can't find victims from proc_app_list.
+                  So, it should search victims or malicious process from /proc.
+                  But searching /proc leads to abnormal behaviour.
+                  (Make sluggish or kill same victims continuously)
+                  Thus, otherwise, just return in first operation and wait some period.
+        */
+       if (cgroup_type == CGROUP_LOW) {
+               cgroup_type = CGROUP_MEDIUM;
+               goto retry;
+       } else if ((cgroup_type == CGROUP_MEDIUM) && (ctl->flags & OOM_IN_DEPTH)) {
+               cgroup_type = CGROUP_HIGH;
+               if(ctl->flags & OOM_FORCE)
+                       max_victim_cnt = FOREGROUND_VICTIMS;
+               goto retry;
+       } else if ((cgroup_type == CGROUP_HIGH) && (ctl->flags & OOM_IN_DEPTH)) {
+               status = LOWMEM_RECLAIM_RETRY;
+               ctl->type = CGROUP_ROOT;
+       }
+       else if (cgroup_type == CGROUP_ROOT) {
+               status = LOWMEM_RECLAIM_RETRY;
+       }
+done:
+       _I("[LMK] Done: killed %d processes reclaimed=%uMB remaining=%uMB shortfall=%uMB status=%s",
+               count, total_size, reclaim_size, shortfall, convert_status_to_str(status));
+
+       /* After we finish reclaiming it's worth to remove oldest memps logs */
+       if (count && memlog_enabled)
+               request_helper_worker(CLEAR_LOGS, memlog_path, clear_logs, NULL);
+       ctl->status = status;
+}
+
+static void *lowmem_reclaim_worker(void *arg)
+{
+       struct lowmem_worker *lmw = (struct lowmem_worker *)arg;
+
+       setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
+
+       g_async_queue_ref(lmw->queue);
+
+       while (1) {
+               int try_count = 0;
+               struct lowmem_control *ctl;
+
+               LOWMEM_WORKER_IDLE(lmw);
+               /* Wait on any wake-up call */
+               ctl = g_async_queue_pop(lmw->queue);
+
+               if (ctl->flags & OOM_DROP)
+                       LOWMEM_DESTROY_REQUEST(ctl);
+
+               if (!LOWMEM_WORKER_IS_ACTIVE(lmw) || !ctl)
+                       break;
+
+               LOWMEM_WORKER_RUN(lmw);
+process_again:
+               _D("[LMK] %d tries", ++try_count);
+               lowmem_handle_request(ctl);
+               /**
+                * Case the process failed to reclaim requested amount of memory
+                * or still under have memory pressure - try the timeout wait.
+                * There is a chance this will get woken-up in a better reality.
+                */
+               if (ctl->status == LOWMEM_RECLAIM_RETRY &&
+                   !(ctl->flags & OOM_SINGLE_SHOT)) {
+                       unsigned int available = proc_get_mem_available();
+
+                       if (available >= ctl->size) {
+                               _I("[LMK] Memory restored: requested=%uMB available=%uMB\n",
+                                       ctl->size, available);
+                               ctl->status = LOWMEM_RECLAIM_DONE;
+                               if (ctl->callback)
+                                       ctl->callback(ctl);
+                               LOWMEM_DESTROY_REQUEST(ctl);
+                               LOWMEM_WORKER_IDLE(lmw);
+                               continue;
+                       }
+
+                       if (LOWMEM_WORKER_IS_ACTIVE(lmw)) {
+                               g_usleep(LMW_RETRY_WAIT_TIMEOUT_MSEC);
+                               ctl->flags |= OOM_REVISE;
+                               goto process_again;
+                       }
+               }
+
+               /*
+                * The ctl callback would check available size again.
+                * And it is last point in reclaiming worker.
+                * Resourced sent SIGKILL signal to victim processes
+                * so it should wait for a some seconds until each processes returns memory.
+                */
+               g_usleep(LMW_LOOP_WAIT_TIMEOUT_MSEC);
+               if (ctl->callback)
+                       ctl->callback(ctl);
+
+               /* The lmk becomes the owner of all queued requests .. */
+               LOWMEM_DESTROY_REQUEST(ctl);
+               LOWMEM_WORKER_IDLE(lmw);
+       }
+       g_async_queue_unref(lmw->queue);
+       pthread_exit(NULL);
+}
+
+static void change_lowmem_state(unsigned int mem_state)
+{
+       cur_mem_state = mem_state;
+       lmk_start_threshold = get_root_memcg_info()->threshold[MEM_LEVEL_OOM];
+
+       resourced_notify(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
+               (void *)&cur_mem_state);
+}
+
+/* only app can call this function
+ * that is, service cannot call the function
+ */
+static void lowmem_swap_memory(char *path)
+{
+       unsigned int available;
+
+       if (cur_mem_state == MEM_LEVEL_HIGH)
+               return;
+
+       if (swap_get_state() != SWAP_ON)
+               return;
+
+       available = proc_get_mem_available();
+       if (cur_mem_state != MEM_LEVEL_LOW &&
+           available <= get_root_memcg_info()->threshold[MEM_LEVEL_LOW])
+               swap_activate_act();
+
+       resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
+       memcg_swap_status = true;
+}
+
+void lowmem_trigger_swap(pid_t pid, char *path, bool move)
+{
+       int error;
+       int oom_score_adj;
+       int lowest_oom_score_adj;
+
+       if (!path) {
+               _E("[SWAP] Unknown memory cgroup path to swap");
+               return;
+       }
+
+       /* In this case, corresponding process will be moved to memory CGROUP_LOW.
+        */
+       if (move) {
+               error = proc_get_oom_score_adj(pid, &oom_score_adj);
+               if (error) {
+                       _E("[SWAP] Cannot get oom_score_adj of pid (%d)", pid);
+                       return;
+               }
+
+               lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(CGROUP_LOW);
+
+               if (oom_score_adj < lowest_oom_score_adj) {
+                       oom_score_adj = lowest_oom_score_adj;
+                       /* End of this funciton, 'lowmem_swap_memory()' funciton will be called */
+                       proc_set_oom_score_adj(pid, oom_score_adj, find_app_info(pid));
+                       return;
+               }
+       }
+
+       /* Correponding process is already managed per app or service.
+        * In addition, if some process is already located in the CGROUP_LOW, then just do swap
+        */
+       resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
+}
+
+static void memory_level_send_system_event(int lv)
+{
+       bundle *b;
+       const char *str;
+
+       switch (lv) {
+               case MEM_LEVEL_HIGH:
+               case MEM_LEVEL_MEDIUM:
+               case MEM_LEVEL_LOW:
+                       str = EVT_VAL_MEMORY_NORMAL;
+                       break;
+               case MEM_LEVEL_CRITICAL:
+                       str = EVT_VAL_MEMORY_SOFT_WARNING;
+                       break;
+               case MEM_LEVEL_OOM:
+                       str = EVT_VAL_MEMORY_HARD_WARNING;
+                       break;
+               default:
+                       _E("Invalid state");
+                       return;
+       }
+
+       b = bundle_create();
+       if (!b) {
+               _E("Failed to create bundle");
+               return;
+       }
+
+       bundle_add_str(b, EVT_KEY_LOW_MEMORY, str);
+       eventsystem_send_system_event(SYS_EVENT_LOW_MEMORY, b);
+       bundle_free(b);
+}
+
+static void high_mem_act(void)
+{
+       int ret, status;
+
+       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+       if (ret)
+               _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
+               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                             VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+               memory_level_send_system_event(MEM_LEVEL_HIGH);
+       }
+
+       change_lowmem_state(MEM_LEVEL_HIGH);
+
+       if (swap_get_state() == SWAP_ON && memcg_swap_status) {
+               resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, get_memcg_info(CGROUP_LOW));
+               memcg_swap_status = false;
+       }
+       if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
+               resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+                       (void *)CGROUP_FREEZER_ENABLED);
+}
+
+static void swap_activate_act(void)
+{
+       int ret, status;
+
+       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+       if (ret)
+               _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
+               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                               VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+               memory_level_send_system_event(MEM_LEVEL_LOW);
+       }
+       change_lowmem_state(MEM_LEVEL_LOW);
+       if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
+               resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+                       (void *)CGROUP_FREEZER_ENABLED);
+
+       if (swap_get_state() != SWAP_ON)
+               resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
+}
+
+static void dedup_act(enum ksm_scan_mode mode)
+{
+       int ret, status;
+       int data;
+
+       if (dedup_get_state() != DEDUP_ONE_SHOT)
+               return;
+
+       if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
+               resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+                               (void *)CGROUP_FREEZER_ENABLED);
+
+       if (mode == KSM_SCAN_PARTIAL) {
+               ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+               if (ret)
+                       _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+               if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
+                       vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                                       VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+                       memory_level_send_system_event(MEM_LEVEL_MEDIUM);
+               }
+               change_lowmem_state(MEM_LEVEL_MEDIUM);
+
+               data = KSM_SCAN_PARTIAL;
+               resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
+       } else if (mode == KSM_SCAN_FULL) {
+               data = KSM_SCAN_FULL;
+               resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
+       }
+}
+
+static void swap_compact_act(void)
+{
+       change_lowmem_state(MEM_LEVEL_CRITICAL);
+       resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_CRITICAL);
+       memory_level_send_system_event(MEM_LEVEL_CRITICAL);
+}
+
+static void medium_cb(struct lowmem_control *ctl)
+{
+       if (ctl->status == LOWMEM_RECLAIM_DONE)
+               oom_popup = false;
+       lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
+}
+
+static void lmk_act(void)
+{
+       unsigned int available;
+       int ret;
+       int status = VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL;
+
+       /*
+        * Don't trigger reclaim worker
+        * if it is already running
+        */
+       if (LOWMEM_WORKER_IS_RUNNING(&lmw))
+               return;
+
+       ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+       if (ret)
+               _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+       memory_level_send_system_event(MEM_LEVEL_OOM);
+       if (status != VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING) {
+               if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
+                       resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+                               (void *)CGROUP_FREEZER_PAUSED);
+               vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+                             VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
+       }
+       available = proc_get_mem_available();
+
+       change_lowmem_state(MEM_LEVEL_OOM);
+
+       if (available < get_root_memcg_info()->threshold_leave) {
+               struct lowmem_control *ctl;
+
+               ctl = LOWMEM_NEW_REQUEST();
+               if (ctl) {
+                       LOWMEM_SET_REQUEST(ctl, OOM_IN_DEPTH,
+                               CGROUP_LOW, get_root_memcg_info()->threshold_leave,
+                               num_max_victims, medium_cb);
+                       lowmem_queue_request(&lmw, ctl);
+               }
+       }
+
+       resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_OOM);
+
+       /*
+        * Flush resourced memory such as other processes.
+        * Resourced can use both many fast bins and sqlite3 cache memery.
+        */
+       malloc_trim(0);
+
+       return;
+}
+
+static void lowmem_trigger_memory_state_action(int mem_state)
+{
+       /*
+        * Check if the state we want to set is different from current
+        * But it should except this condition if mem_state is already medium.
+        * Otherwise, recalim worker couldn't run any more.
+        */
+       if (mem_state != MEM_LEVEL_OOM && cur_mem_state == mem_state)
+               return;
+
+       switch (mem_state) {
+       case MEM_LEVEL_HIGH:
+               high_mem_act();
+               break;
+       case MEM_LEVEL_MEDIUM:
+               dedup_act(KSM_SCAN_PARTIAL);
+               break;
+       case MEM_LEVEL_LOW:
+               swap_activate_act();
+               break;
+       case MEM_LEVEL_CRITICAL:
+               dedup_act(KSM_SCAN_FULL);
+               swap_compact_act();
+               break;
+       case MEM_LEVEL_OOM:
+               lmk_act();
+               break;
+       default:
+               assert(0);
+       }
+}
+
+static void lowmem_dump_cgroup_procs(struct memcg_info *mi)
+{
+       int i;
+       unsigned int size;
+       pid_t pid;
+       GArray *pids_array = NULL;
+
+       cgroup_get_pids(mi->name, &pids_array);
+
+       for (i = 0; i < pids_array->len; i++) {
+               pid = g_array_index(pids_array, pid_t, i);
+               lowmem_mem_usage_uss(pid, &size);
+               _I("pid = %d, size = %u KB", pid, size);
+       }
+       g_array_free(pids_array, true);
+}
+
+static void memory_cgroup_proactive_lmk_act(enum cgroup_type type, struct memcg_info *mi)
+{
+       struct lowmem_control *ctl;
+
+       /* To Do: only start to kill fg victim when no pending fg victim */
+       lowmem_dump_cgroup_procs(mi);
+
+       ctl = LOWMEM_NEW_REQUEST();
+       if (ctl) {
+               LOWMEM_SET_REQUEST(ctl, OOM_SINGLE_SHOT | OOM_IN_DEPTH, type,
+                       mi->oomleave, num_max_victims, NULL);
+               lowmem_queue_request(&lmw, ctl);
+       }
+}
+
+static unsigned int check_mem_state(unsigned int available)
+{
+       int mem_state;
+       for (mem_state = MEM_LEVEL_MAX - 1; mem_state > MEM_LEVEL_HIGH; mem_state--) {
+               if (mem_state != MEM_LEVEL_OOM && available <= get_root_memcg_info()->threshold[mem_state])
+                       break;
+               else if (mem_state == MEM_LEVEL_OOM && available <= lmk_start_threshold)
+                       break;
+       }
+
+       return mem_state;
+}
+
+/*static int load_bg_reclaim_config(struct parse_result *result, void *user_data)
+{
+       if (!result)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (strncmp(result->section, MEM_BG_RECLAIM_SECTION, strlen(MEM_BG_RECLAIM_SECTION)+1))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strncmp(result->name, MEM_BG_RECLAIM_STRING, strlen(MEM_BG_RECLAIM_STRING)+1)) {
+               if (!strncmp(result->value, "yes", strlen("yes")+1))
+                       bg_reclaim = true;
+               else if (!strncmp(result->value, "no", strlen("no")+1))
+                       bg_reclaim = false;
+       }
+
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int load_popup_config(struct parse_result *result, void *user_data)
+{
+       if (!result)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (strncmp(result->section, MEM_POPUP_SECTION, strlen(MEM_POPUP_SECTION)+1))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strncmp(result->name, MEM_POPUP_STRING, strlen(MEM_POPUP_STRING)+1)) {
+               if (!strncmp(result->value, "yes", strlen("yes")+1))
+                       oom_popup_enable = true;
+               else if (!strncmp(result->value, "no", strlen("no")+1))
+                       oom_popup_enable = false;
+       }
+
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int load_mem_log_config(struct parse_result *result, void *user_data)
+{
+       if (!result)
+               return RESOURCED_ERROR_INVALID_PARAMETER;
+
+       if (strncmp(result->section, MEM_LOGGING_SECTION, strlen(MEM_LOGGING_SECTION)+1))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strncmp(result->name, "Enable", strlen("Enable")+1)) {
+               memlog_enabled = atoi(result->value);
+       } else if (!strncmp(result->name, "LogPath", strlen("LogPath")+1)) {
+               memlog_path = strdup(result->value);
+       } else if (!strncmp(result->name, "MaxNumLogfile", strlen("MaxNumLogfile")+1)) {
+               memlog_nr_max = atoi(result->value);
+               memlog_remove_batch_thres = (memlog_nr_max * 5) / 6;
+       } else if (!strncmp(result->name, "PrefixMemps", strlen("PrefixMemps")+1)) {
+               memlog_prefix[MEMLOG_MEMPS] = strdup(result->value);
+       } else if (!strncmp(result->name, "PrefixMempsMemLimit", strlen("PrefixMempsMemLimit")+1)) {
+               memlog_prefix[MEMLOG_MEMPS_MEMLIMIT] = strdup(result->value);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int set_memory_config(struct parse_result *result, void *user_data)
+{
+       if (!result)
+               return RESOURCED_ERROR_NONE;
+
+       if (strncmp(result->section, MEM_SECTION, strlen(MEM_SECTION)+1))
+               return RESOURCED_ERROR_NONE;
+
+       if (!strncmp(result->name, "ThresholdDedup", strlen("ThresholdDedup")+1)) {
+               int value = atoi(result->value);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, value);
+       } else if (!strncmp(result->name, "ThresholdSwap", strlen("ThresholdSwap")+1)) {
+               int value = atoi(result->value);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, value);
+       } else if (!strncmp(result->name, "ThresholdLow", strlen("ThresholdLow")+1)) {
+               int value = atoi(result->value);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, value);
+       } else if (!strncmp(result->name, "ThresholdMedium", strlen("ThresholdMedium")+1)) {
+               int value = atoi(result->value);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, value);
+       } else if (!strncmp(result->name, "ThresholdLeave", strlen("ThresholdLeave")+1)) {
+               int value = atoi(result->value);
+               memcg_set_leave_threshold(CGROUP_ROOT, value);
+       } else if (!strncmp(result->name, "ThresholdRatioDedup", strlen("ThresholdRatioDedup")+1)) {
+               double ratio = atoi(result->value);
+               int value = (double)totalram * ratio / 100.0;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, BYTE_TO_MBYTE(value));
+       } else if (!strncmp(result->name, "ThresholdRatioSwap", strlen("ThresholdRatioSwap")+1)) {
+               double ratio = atoi(result->value);
+               int value = (double)totalram * ratio / 100.0;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, BYTE_TO_MBYTE(value));
+       } else if (!strncmp(result->name, "ThresholdRatioLow", strlen("ThresholdRatioLow")+1)) {
+               double ratio = atoi(result->value);
+               int value = (double)totalram * ratio / 100.0;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, BYTE_TO_MBYTE(value));
+       } else if (!strncmp(result->name, "ThresholdRatioMedium", strlen("ThresholdRatioMedium")+1)) {
+               double ratio = atoi(result->value);
+               int value = (double)totalram * ratio / 100.0;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, BYTE_TO_MBYTE(value));
+       } else if (!strncmp(result->name, "ThresholdRatioLeave", strlen("ThresholdRatioLeave")+1)) {
+               double ratio = atoi(result->value);
+               int value = (double)totalram * ratio / 100.0;
+               memcg_set_leave_threshold(CGROUP_ROOT, BYTE_TO_MBYTE(value));
+       } else if (!strncmp(result->name, "ForegroundRatio", strlen("ForegroundRatio")+1)) {
+               float ratio = atof(result->value);
+               memcg_info_set_limit(get_memcg_info(CGROUP_HIGH), ratio, totalram);
+       } else if (!strncmp(result->name, "BackgroundRatio", strlen("BackgroundRatio")+1)) {
+               float ratio = atof(result->value);
+               memcg_info_set_limit(get_memcg_info(CGROUP_MEDIUM), ratio, totalram);
+       } else if (!strncmp(result->name, "LowRatio", strlen("LowRatio")+1)) {
+               float ratio = atof(result->value);
+               memcg_info_set_limit(get_memcg_info(CGROUP_LOW), ratio, totalram);
+       } else if (!strncmp(result->name, "NumMaxVictims", strlen("NumMaxVictims")+1)) {
+               int value = atoi(result->value);
+               num_max_victims = value;
+               num_vict_between_check = value > MAX_MEMORY_CGROUP_VICTIMS/2
+                                               ? 3 : value > MAX_MEMORY_CGROUP_VICTIMS/4
+                                                               ? 2 : 1;
+       } else if (!strncmp(result->name, "ProactiveThreshold", strlen("ProactiveThreshold")+1)) {
+               int value = atoi(result->value);
+               proactive_threshold = value;
+       } else if (!strncmp(result->name, "ProactiveLeave", strlen("ProactiveLeave")+1)) {
+               int value = atoi(result->value);
+               proactive_leave = value;
+       } else if (!strncmp(result->name, "EventLevel", strlen("EventLevel")+1)) {
+               if (strncmp(event_level, result->value, strlen(event_level)))
+                       event_level = strdup(result->value);
+               if (!event_level)
+                       return RESOURCED_ERROR_OUT_OF_MEMORY;
+       } else if (!strncmp(result->name, "SWAPPINESS", strlen("SWAPPINESS")+1)) {
+               int value = atoi(result->value);
+               memcg_set_default_swappiness(value);
+               memcg_info_set_swappiness(get_memcg_info(CGROUP_ROOT), value);
+       } else if (!strncmp(result->name, "FOREGROUND_SWAPPINESS", strlen("FOREGROUND_SWAPPINESS")+1)) {
+               int value = atoi(result->value);
+               memcg_info_set_swappiness(get_memcg_info(CGROUP_HIGH), value);
+       } else if (!strncmp(result->name, "BACKGROUND_SWAPPINESS", strlen("BACKGROUND_SWAPPINESS")+1)) {
+               int value = atoi(result->value);
+               memcg_info_set_swappiness(get_memcg_info(CGROUP_MEDIUM), value);
+       } else if (!strncmp(result->name, "LOW_SWAPPINESS", strlen("LOW_SWAPPINESS")+1)) {
+               int value = atoi(result->value);
+               memcg_info_set_swappiness(get_memcg_info(CGROUP_LOW), value);
+       } else if (!strncmp(result->name, "NumFragSize", strlen("NumFragSize")+1)) {
+               fragmentation_size = atoi(result->value);
+       }
+
+       return RESOURCED_ERROR_NONE;
+}*/
+
+/* setup memcg parameters depending on total ram size. */
+static void setup_memcg_params(void)
+{
+       unsigned long long total_ramsize;
+
+       get_total_memory();
+       total_ramsize = BYTE_TO_MBYTE(totalram);
+
+       _D("Total: %llu MB", total_ramsize);
+       if (total_ramsize <= MEM_SIZE_64) {
+               /* set thresholds for ram size 64M */
+               proactive_threshold = PROACTIVE_64_THRES;
+               proactive_leave = PROACTIVE_64_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_64_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_64_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_64_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_64_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_64_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_64_NUM_VICTIMS;
+       } else if (total_ramsize <= MEM_SIZE_256) {
+               /* set thresholds for ram size 256M */
+               proactive_threshold = PROACTIVE_256_THRES;
+               proactive_leave = PROACTIVE_256_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_256_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_256_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_256_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_256_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_256_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_256_NUM_VICTIMS;
+       } else if (total_ramsize <= MEM_SIZE_448) {
+               /* set thresholds for ram size 448M */
+               proactive_threshold = PROACTIVE_448_THRES;
+               proactive_leave = PROACTIVE_448_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_448_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_448_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_448_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_448_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_448_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_448_NUM_VICTIMS;
+       } else if (total_ramsize <= MEM_SIZE_512) {
+               /* set thresholds for ram size 512M */
+               proactive_threshold = PROACTIVE_512_THRES;
+               proactive_leave = PROACTIVE_512_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_512_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_512_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_512_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_512_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_512_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_512_NUM_VICTIMS;
+       }  else if (total_ramsize <= MEM_SIZE_768) {
+               /* set thresholds for ram size 512M */
+               proactive_threshold = PROACTIVE_768_THRES;
+               proactive_leave = PROACTIVE_768_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_768_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_768_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_768_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_768_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_768_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_768_NUM_VICTIMS;
+       } else if (total_ramsize <= MEM_SIZE_1024) {
+               /* set thresholds for ram size more than 1G */
+               proactive_threshold = PROACTIVE_1024_THRES;
+               proactive_leave = PROACTIVE_1024_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_1024_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_1024_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_1024_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_1024_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_1024_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_1024_NUM_VICTIMS;
+       } else if (total_ramsize <= MEM_SIZE_2048) {
+               proactive_threshold = PROACTIVE_2048_THRES;
+               proactive_leave = PROACTIVE_2048_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_2048_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_2048_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_2048_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_2048_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_2048_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_2048_NUM_VICTIMS;
+       } else {
+               proactive_threshold = PROACTIVE_3072_THRES;
+               proactive_leave = PROACTIVE_3072_LEAVE;
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_3072_THRES_DEDUP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_3072_THRES_SWAP);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_3072_THRES_LOW);
+               memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_3072_THRES_MEDIUM);
+               memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_3072_THRES_LEAVE);
+               num_max_victims = CGROUP_ROOT_3072_NUM_VICTIMS;
+       }
+
+}
+
+static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
+{
+       int cur_oom_score_adj;
+       int cur_memcg_idx;
+       struct memcg_info *mi;
+       int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
+
+       if(next_memcg_idx < CGROUP_VIP || next_memcg_idx > CGROUP_LOW) {
+               _E("cgroup type (%d) should not be called", next_memcg_idx);
+               return;
+       }
+       mi = get_memcg_info(next_memcg_idx);
+
+       if (!mi) {
+               return;
+       }
+
+       if (!pai) {
+               cgroup_write_pid_fullpath(mi->name, pid);
+               return;
+       }
+
+       /* parent pid */
+       if (pai->main_pid == pid) {
+               cur_oom_score_adj = pai->memory.oom_score_adj;
+               cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
+
+               /* -1 means that this pid is not yet registered at the memory cgroup
+                * plz, reference proc_create_app_info function
+                */
+               if (cur_oom_score_adj != OOMADJ_APP_MAX + 10) {
+                       /* VIP processes should not be asked to move. */
+                       if (cur_memcg_idx <= CGROUP_VIP) {
+                               _I("[DEBUG] pid: %d, name: %s, cur_oom_score_adj: %d", pid, pai->appid, cur_oom_score_adj);
+                               _E("[DEBUG] current cgroup (%s) cannot be VIP or Root", convert_cgroup_type_to_str(cur_memcg_idx));
+                               return;
+                       }
+               }
+
+               _I("app (%s) memory cgroup move from %s to %s", pai->appid, convert_cgroup_type_to_str(cur_memcg_idx), convert_cgroup_type_to_str(next_memcg_idx));
+
+               if (cur_oom_score_adj == next_oom_score_adj) {
+                       _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
+                       return;
+               }
+
+               proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
+
+               if (!lowmem_limit_move_cgroup(pai))
+                       return;
+
+               if(cur_memcg_idx == next_memcg_idx)
+                       return;
+
+               cgroup_write_pid_fullpath(mi->name, pid);
+               if (next_memcg_idx == CGROUP_LOW)
+                       lowmem_swap_memory(get_memcg_info(CGROUP_LOW)->name);
+       }
+       /* child pid */
+       else {
+               if (pai->memory.use_mem_limit)
+                       return;
+
+               cgroup_write_pid_fullpath(mi->name, pid);
+       }
+}
+
+static int lowmem_activate_worker(void)
+{
+       int ret = RESOURCED_ERROR_NONE;
+
+       if (LOWMEM_WORKER_IS_ACTIVE(&lmw)) {
+               return ret;
+       }
+
+       lmw.queue = g_async_queue_new_full(lowmem_request_destroy);
+       if (!lmw.queue) {
+               _E("Failed to create request queue\n");
+               return RESOURCED_ERROR_FAIL;
+       }
+       LOWMEM_WORKER_ACTIVATE(&lmw);
+       ret = pthread_create(&lmw.worker_thread, NULL,
+               (void *)lowmem_reclaim_worker, (void *)&lmw);
+       if (ret) {
+               LOWMEM_WORKER_DEACTIVATE(&lmw);
+               _E("Failed to create LMK thread: %d\n", ret);
+       } else {
+               pthread_detach(lmw.worker_thread);
+               ret = RESOURCED_ERROR_NONE;
+       }
+       return ret;
+}
+
+static void lowmem_deactivate_worker(void)
+{
+       struct lowmem_control *ctl;
+
+       if (!LOWMEM_WORKER_IS_ACTIVE(&lmw))
+               return;
+
+       LOWMEM_WORKER_DEACTIVATE(&lmw);
+       lowmem_drain_queue(&lmw);
+
+       ctl = LOWMEM_NEW_REQUEST();
+       if (!ctl) {
+               _E("Critical - g_slice alloc failed - Lowmem cannot be deactivated");
+               return;
+       }
+       ctl->flags = OOM_DROP;
+       g_async_queue_push(lmw.queue, ctl);
+       g_async_queue_unref(lmw.queue);
+}
+
+static int lowmem_press_eventfd_read(int fd)
+{
+       uint64_t dummy_state;
+
+       return read(fd, &dummy_state, sizeof(dummy_state));
+}
+
+static void lowmem_press_root_cgroup_handler(void)
+{
+       static unsigned int prev_available;
+       unsigned int available;
+       int mem_state;
+
+       available = proc_get_mem_available();
+       if (prev_available == available)
+               return;
+
+       mem_state = check_mem_state(available);
+       lowmem_trigger_memory_state_action(mem_state);
+
+       prev_available = available;
+}
+
+static void lowmem_press_cgroup_handler(enum cgroup_type type, struct memcg_info *mi)
+{
+       unsigned int usage, threshold;
+       int ret;
+
+       ret = memcg_get_anon_usage(mi->name, &usage);
+       if (ret) {
+               _D("getting anonymous memory usage fails");
+               return;
+       }
+
+       threshold = mi->threshold[MEM_LEVEL_OOM];
+       if (usage >= threshold)
+               memory_cgroup_proactive_lmk_act(type, mi);
+       else
+               _I("anon page %u MB < medium threshold %u MB", BYTE_TO_MBYTE(usage),
+                               BYTE_TO_MBYTE(threshold));
+}
+
+static bool lowmem_press_eventfd_handler(int fd, void *data)
+{
+       struct memcg_info *mi;
+       enum cgroup_type type = CGROUP_ROOT;
+
+       // FIXME: probably shouldn't get ignored
+       if (lowmem_press_eventfd_read(fd) < 0)
+               _E("Failed to read lowmem press event, %m\n");
+
+       for (type = CGROUP_ROOT; type < CGROUP_END; type++) {
+               if (!get_cgroup_tree(type) || !get_memcg_info(type))
+                       continue;
+               mi = get_memcg_info(type);
+               if (fd == mi->evfd) {
+                       /* call low memory handler for this memcg */
+                       if (type == CGROUP_ROOT)
+                               lowmem_press_root_cgroup_handler();
+                       else {
+                               lowmem_press_cgroup_handler(type, mi);
+                       }
+                       return true;
+               }
+       }
+
+       return true;
+}
+
+static int lowmem_press_register_eventfd(struct memcg_info *mi)
+{
+       int evfd;
+       const char *name = mi->name;
+       static fd_handler_h handler;
+
+       if (mi->threshold[MEM_LEVEL_OOM] == LOWMEM_THRES_INIT)
+               return 0;
+
+       evfd = memcg_set_eventfd(name, MEMCG_EVENTFD_MEMORY_PRESSURE,
+                       event_level);
+
+       if (evfd < 0) {
+               int saved_errno = errno;
+               _E("fail to register event press fd %s cgroup", name);
+               return -saved_errno;
+       }
+
+       mi->evfd = evfd;
+
+       _I("register event fd success for %s cgroup", name);
+       add_fd_read_handler(evfd, lowmem_press_eventfd_handler, NULL, NULL, &handler);
+       return 0;
+}
+
+static int lowmem_press_setup_eventfd(void)
+{
+       unsigned int i;
+
+       for (i = CGROUP_ROOT; i < CGROUP_END; i++) {
+               if (!get_use_hierarchy(i))
+                       continue;
+
+               lowmem_press_register_eventfd(get_memcg_info(i));
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static void lowmem_force_reclaim_cb(struct lowmem_control *ctl)
+{
+       lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
+}
+
+int lowmem_trigger_reclaim(int flags, int victims, enum cgroup_type type, int threshold)
+{
+       struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
+
+       if (!ctl)
+               return -ENOMEM;
+
+       flags |= OOM_FORCE | OOM_IN_DEPTH | OOM_SINGLE_SHOT;
+       victims = victims > 0 ? victims : MAX_MEMORY_CGROUP_VICTIMS;
+       type = type > 0 ? type : CGROUP_LOW;
+       threshold = threshold > 0 ? threshold : get_root_memcg_info()->threshold_leave;
+
+       lowmem_change_memory_state(MEM_LEVEL_CRITICAL, 1);
+       LOWMEM_SET_REQUEST(ctl, flags,
+               type, threshold, victims,
+               lowmem_force_reclaim_cb);
+       lowmem_queue_request(&lmw, ctl);
+
+       return 0;
+}
+
+void lowmem_trigger_swap_reclaim(enum cgroup_type type, int swap_size)
+{
+       int size, victims;
+
+       victims = num_max_victims  > MAX_PROACTIVE_HIGH_VICTIMS
+                                ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
+
+       size = get_root_memcg_info()->threshold_leave + BYTE_TO_MBYTE(swap_size);
+       _I("reclaim from swap module, type : %d, size : %d, victims: %d", type, size, victims);
+       lowmem_trigger_reclaim(0, victims, type, size);
+}
+
+bool lowmem_fragmentated(void)
+{
+       struct buddyinfo bi;
+       int ret;
+
+       ret = proc_get_buddyinfo("Normal", &bi);
+       if (ret < 0)
+               return false;
+
+       /*
+        * The fragmentation_size is the minimum count of order-2 pages in "Normal" zone.
+        * If total buddy pages is smaller than fragmentation_size,
+        * resourced will detect kernel memory is fragmented.
+        * Default value is zero in low memory device.
+        */
+       if (bi.page[PAGE_32K] + (bi.page[PAGE_64K] << 1) + (bi.page[PAGE_128K] << 2) +
+               (bi.page[PAGE_256K] << 3) < fragmentation_size) {
+               _I("fragmentation detected, need to execute proactive oom killer");
+               return true;
+       }
+       return false;
+}
+
+static void lowmem_proactive_oom_killer(int flags, char *appid)
+{
+       unsigned int before;
+       int victims;
+
+       before = proc_get_mem_available();
+
+       /* If memory state is medium or normal, just return and kill in oom killer */
+       if (before < get_root_memcg_info()->threshold[MEM_LEVEL_OOM] || before > proactive_leave)
+               return;
+
+       victims = num_max_victims  > MAX_PROACTIVE_HIGH_VICTIMS
+                                ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
+
+#ifdef HEART_SUPPORT
+       /*
+        * This branch is used only when HEART module is compiled in and
+        * it's MEMORY module must be enabled. Otherwise this is skipped.
+        */
+       struct heart_memory_data *md = heart_memory_get_memdata(appid, DATA_LATEST);
+       if (md) {
+               unsigned int rss, after, size;
+
+               rss = KBYTE_TO_MBYTE(md->avg_rss);
+
+               free(md);
+
+               after = before - rss;
+               /*
+                * after launching app, ensure that available memory is
+                * above threshold_leave
+                */
+               if (after >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
+                       return;
+
+               if (proactive_threshold - rss >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
+                       size = proactive_threshold;
+               else
+                       size = rss + get_root_memcg_info()->threshold[MEM_LEVEL_OOM] + THRESHOLD_MARGIN;
+
+               _D("history based proactive LMK : avg rss %u, available %u required = %u MB",
+                       rss, before, size);
+               lowmem_trigger_reclaim(0, victims, CGROUP_LOW, size);
+
+               return;
+       }
+#endif
+
+       /*
+        * When there is no history data for the launching app,
+        * it is necessary to check current fragmentation state or application manifest file.
+        * So, resourced feels proactive LMK is required, run oom killer based on dynamic
+        * threshold.
+        */
+       if (lowmem_fragmentated())
+               goto reclaim;
+
+       /*
+        * run proactive oom killer only when available is larger than
+        * dynamic process threshold
+        */
+       if (!proactive_threshold || before >= proactive_threshold)
+               return;
+
+       if (!(flags & PROC_LARGEMEMORY))
+               return;
+
+reclaim:
+       /*
+        * free THRESHOLD_MARGIN more than real should be freed,
+        * because launching app is consuming up the memory.
+        */
+       _D("Run threshold based proactive LMK: memory level to reach: %u\n",
+               proactive_leave + THRESHOLD_MARGIN);
+       lowmem_trigger_reclaim(0, victims, CGROUP_LOW, proactive_leave + THRESHOLD_MARGIN);
+}
+
+unsigned int lowmem_get_proactive_thres(void)
+{
+       return proactive_threshold;
+}
+
+static int lowmem_prelaunch_handler(void *data)
+{
+       struct proc_status *ps = (struct proc_status *)data;
+       struct proc_app_info *pai = ps->pai;
+
+       if (!pai || CHECK_BIT(pai->flags, PROC_SERVICEAPP))
+               return RESOURCED_ERROR_NONE;
+
+       lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid);
+       return RESOURCED_ERROR_NONE;
+}
+
+int lowmem_control_handler(void *data)
+{
+       struct lowmem_control_data *lowmem_data;
+
+       lowmem_data = (struct lowmem_control_data *)data;
+       switch (lowmem_data->control_type) {
+       case LOWMEM_MOVE_CGROUP:
+               lowmem_move_memcgroup((pid_t)lowmem_data->pid,
+                                       lowmem_data->oom_score_adj, lowmem_data->pai);
+               break;
+       default:
+               break;
+       }
+       return RESOURCED_ERROR_NONE;
+}
+
+static int lowmem_bg_reclaim_handler(void *data)
+{
+       if (swap_get_state() != SWAP_ON)
+               return RESOURCED_ERROR_NONE;
+
+       if (!bg_reclaim)
+               return RESOURCED_ERROR_NONE;
+
+       /*
+        * Proactively reclaiming memory used by long-lived background processes
+        * (such as widget instances) may be efficient on devices with limited
+        * memory constraints. The pages used by such processes could be reclaimed
+        * (if swap is enabled) earlier than they used to while minimizing the
+        * impact on the user experience.
+        */
+       resourced_notify(RESOURCED_NOTIFIER_SWAP_START, get_memcg_info(CGROUP_MEDIUM)->name);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static void load_configs(const char *path)
+{
+/*     if (config_parse(path, set_memory_config, NULL))
+               _E("(%s-mem) parse Fail", path);
+
+       if (config_parse(path, load_popup_config, NULL))
+               _E("(%s-popup) parse Fail", path);
+
+       if (config_parse(path, load_bg_reclaim_config, NULL))
+               _E("(%s-bg-reclaim) parse Fail", path);
+
+       if (config_parse(path, load_mem_log_config, NULL))
+               _E("(%s-mem-log) parse Fail", path);*/
+
+       free_memcg_conf();
+}
+
+static void print_mem_configs(void)
+{
+       /* print info of Memory section */
+       for (int mem_lvl = 0; mem_lvl < MEM_LEVEL_MAX; mem_lvl++)
+               _I("set threshold for state '%s' to %u MB",
+               convert_memstate_to_str(mem_lvl), get_root_memcg_info()->threshold[mem_lvl]);
+
+       _I("set number of max victims as %d", num_max_victims);
+       _I("set threshold leave to %u MB", get_root_memcg_info()->threshold_leave);
+       _I("set proactive threshold to %u MB", proactive_threshold);
+       _I("set proactive low memory killer leave to %u MB", proactive_leave);
+
+       /* print info of POPUP section */
+       _I("oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
+
+       /* print info of BackgroundReclaim section */
+       _I("Background reclaim is %s", bg_reclaim == true ? "enabled" : "disabled");
+
+       /* print info of Logging section */
+       _I("memory logging is %s", memlog_enabled == 1 ? "enabled" : "disabled");
+       _I("memory logging path is %s", memlog_path);
+       _I("the max number of memory logging is %d", memlog_nr_max);
+       _I("the batch threshold of memory log is %d", memlog_remove_batch_thres);
+       _I("prefix of memps is %s", memlog_prefix[MEMLOG_MEMPS]);
+       _I("prefix of memlimit memps is %s", memlog_prefix[MEMLOG_MEMPS_MEMLIMIT]);
+}
+
+/* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
+static int lowmem_init(void)
+{
+       int ret = RESOURCED_ERROR_NONE;
+
+       _D("resourced memory init start");
+
+       /* init memcg */
+       ret = cgroup_make_full_subdir(MEMCG_PATH);
+       ret_value_msg_if(ret < 0, ret, "memory cgroup init failed\n");
+       memcg_params_init();
+
+       setup_memcg_params();
+
+       /* default configuration */
+       load_configs(MEM_CONF_FILE);
+
+       /* this function should be called after parsing configurations */
+       memcg_write_params();
+       print_mem_configs();
+
+       /* make a worker thread called low memory killer */
+       ret = lowmem_activate_worker();
+       if (ret) {
+               _E("oom thread create failed\n");
+               return ret;
+       }
+
+       /* register threshold and event fd */
+       ret = lowmem_press_setup_eventfd();
+       if (ret) {
+               _E("eventfd setup failed");
+               return ret;
+       }
+
+       lowmem_dbus_init();
+       lowmem_limit_init();
+       lowmem_system_init();
+
+       register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
+       register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
+       register_notifier(RESOURCED_NOTIFIER_LCD_OFF, lowmem_bg_reclaim_handler);
+
+       return ret;
+}
+
+static int lowmem_exit(void)
+{
+       if (strncmp(event_level, MEMCG_DEFAULT_EVENT_LEVEL, sizeof(MEMCG_DEFAULT_EVENT_LEVEL)))
+               free(event_level);
+
+       lowmem_deactivate_worker();
+       lowmem_limit_exit();
+       lowmem_system_exit();
+
+       unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
+       unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
+       unregister_notifier(RESOURCED_NOTIFIER_LCD_OFF, lowmem_bg_reclaim_handler);
+
+       return RESOURCED_ERROR_NONE;
+}
+
+static int resourced_memory_init(void *data)
+{
+       lowmem_ops = &memory_modules_ops;
+       return lowmem_init();
+}
+
+static int resourced_memory_finalize(void *data)
+{
+       return lowmem_exit();
+}
+
+void lowmem_change_memory_state(int state, int force)
+{
+       int mem_state;
+
+       if (force) {
+               mem_state = state;
+       } else {
+               unsigned int available = proc_get_mem_available();
+               mem_state = check_mem_state(available);
+       }
+
+       lowmem_trigger_memory_state_action(mem_state);
+}
+
+unsigned long lowmem_get_ktotalram(void)
+{
+       return ktotalram;
+}
+
+unsigned long lowmem_get_totalram(void)
+{
+       return totalram;
+}
+
+void lowmem_restore_memcg(struct proc_app_info *pai)
+{
+       char *cgpath;
+       int index, ret;
+       struct cgroup *cgroup = NULL;
+       struct memcg_info *mi = NULL;
+       pid_t pid = pai->main_pid;
+
+       ret = cgroup_pid_get_path("memory", pid, &cgpath);
+       if (ret < 0)
+               return;
+
+       for (index = CGROUP_END-1; index >= CGROUP_ROOT; index--) {
+               cgroup = get_cgroup_tree(index);
+               if (!cgroup)
+                       continue;
+
+               mi = cgroup->memcg_info;
+               if (!mi)
+                       continue;
+
+               if (!strcmp(cgroup->hashname, ""))
+                       continue;
+               if (strstr(cgpath, cgroup->hashname))
+                       break;
+       }
+       pai->memory.memcg_idx = index;
+       pai->memory.memcg_info = mi;
+       if(strstr(cgpath, pai->appid))
+               pai->memory.use_mem_limit = true;
+
+       free(cgpath);
+}
+
+static struct module_ops memory_modules_ops = {
+       .priority       = MODULE_PRIORITY_HIGH,
+       .name           = "lowmem",
+       .init           = resourced_memory_init,
+       .exit           = resourced_memory_finalize,
+};
+
+MODULE_REGISTER(&memory_modules_ops)
index 0045afc..35b9d7f 100644 (file)
@@ -1,52 +1,23 @@
-[VIP_PROCESS]
-PREDEFINE=enlightenment
-PREDEFINE=dbus-daemon
-PREDEFINE=amd
-PREDEFINE=launchpad_preloading_preinitializing_daemon
-PREDEFINE=process_pool_launchpad_preloading_preinitializing_daemon
-
-[OOM_FIXED_APPS]
-
-[Memory]
-NumMaxVictims=10
-#ThresholdRatioDedup=30           # %
-#ThresholdRatioSwap=24            # %
-#ThresholdRatioLow=12             # %
-#ThresholdRatioMedium=10          # %
-#ThresholdRatioLeave=15           # %
-#NumMaxVictims=1
-
-[POPUP]
-oom_popup=no
-
-[BackgroundReclaim]
-AfterScreenDim=yes
-
-[MemLimit]
-MemLimitTrigger=oom
-MemLimitService=128                    # MB
-# MemLimitWidget=160                   # MB
-# MemLimitGUIApp=1024                  # MB
-# MemLimitBgApp=768                    # MB
-
-[Logging]
-Enable=0
-MaxNumLogfile=50       # default: 50
-LogPath=/var/log       # default: /var/log
-#PrefixMemps=memps
-#PrefixMempsMemLimit=memps_memlimit
-
-[CPU]
-LAZY_PREDEFINE=net-config
-PREDEFINE=indicator-win
-PREDEFINE=windicator
-BOOTING_PREDEFINE=quickpanel
-WRT_PREDEFINE=wrt_launchpad_daemon
-BOOTING_PREDEFINE=volume
-BOOTING_PREDEFINE=nvitemd
-BACKGROUND_CPU_SHARE=50
-QUOTA_CPU_SHARE=25
-QUOTA_MAX_BANDWIDTH=100
-
-[CPU-SCHED]
-#foreground=1,2,4-6
+[MemoryGroupLimit]
+VipGroupLimit=      100%
+HighGroupLimit=    100%
+MediumGroupLimit=90%
+LowestGroupLimit=  70%
+
+[MemoryLevelThreshold]
+MediumLevel=  400MB
+LowLevel=         300MB
+CriticalLevel=    200MB
+OomLevel=       160MB
+OomPopup=no
+
+[MemoryAppTypeLimit]
+ServicePerAppLimitAction=128MB,kill
+WidgetPerAppLimitAction=160MB,kill
+GUIPerAppLimitAction=1024MB,kill
+
+[MemoryAppStatusLimit]
+BackgroundPerAppLimitAction=768MB,kill
+
+[CpuAffinity]
+ForegroundApps=1,2,4-6
index ed4d217..f9c056a 100644 (file)
@@ -3,20 +3,22 @@
 #include "cpu-cgroup.h"
 #include "trace.h"
 
-static struct cpucg_conf *cpucg_conf;
+static struct cpucg_conf *cpucg_conf = NULL;
 
 char *get_cpucg_conf_name(void)
 {
-       assert(cpucg_conf != NULL);
-
-       return cpucg_conf->name;
+       if (cpucg_conf)
+               return cpucg_conf->name;
+       else
+               return NULL;
 }
 
 char *get_cpucg_conf_value(void)
 {
-       assert(cpucg_conf != NULL);
-
-       return cpucg_conf->value;
+       if (cpucg_conf)
+               return cpucg_conf->value;
+       else
+               return NULL;
 }
 
 int set_cpucg_conf(const char *name, const char *value)
@@ -44,9 +46,8 @@ int set_cpucg_conf(const char *name, const char *value)
 
 void free_cpucg_conf(void)
 {
-       assert(cpucg_conf != NULL);
-       
-       free(cpucg_conf);
+       if (cpucg_conf) 
+               free(cpucg_conf);
 }
 
 static int cpu_move_cgroup(pid_t pid, char *path)
index 13c48b4..e800662 100644 (file)
@@ -131,19 +131,19 @@ int set_memcg_conf_threshold(bool percent, char size, int lvl, const char *value
        if (!percent) {
                if (size == 'G') {
                        memcg_conf->threshold[lvl].threshold = 
-                               GBYTE_TO_BYTE(atoi(value));
+                               GBYTE_TO_MBYTE(atoi(value));
                }
                else if (size == 'M') {
                        memcg_conf->threshold[lvl].threshold = 
-                               MBYTE_TO_BYTE(atoi(value));
+                               atoi(value);
                }
                else if (size == 'K') {
                        memcg_conf->threshold[lvl].threshold = 
-                               KBYTE_TO_BYTE(atoi(value));
+                               KBYTE_TO_MBYTE(atoi(value));
                }
                else if (size == ' ') {
                        memcg_conf->threshold[lvl].threshold = 
-                               atoi(value);
+                               BYTE_TO_MBYTE(atoi(value));
                }
                else {
                        _E("Memory size unit should be GB or MB or KB or B");
@@ -173,9 +173,8 @@ struct memcg_conf *get_memcg_conf(void)
 
 void free_memcg_conf(void)
 {
-       assert(memcg_conf != NULL);
-
-       free(memcg_conf);
+       if (memcg_conf)
+               free(memcg_conf);
 }
 
 static void set_limit_in_bytes(const char *dir, unsigned int limit)
@@ -302,8 +301,10 @@ void memcg_info_set_limit(struct memcg_info *mi, float ratio,
        if (!mi)
                return;
 
+
        mi->limit = (float)totalram * ratio;
        mi->limit_ratio = ratio;
+       _I("[DEBUG] ratio = %f, limit = %u, ram = %u", ratio, mi->limit, totalram);
        mi->threshold[MEM_LEVEL_CRITICAL] = (unsigned int)(mi->limit * MEMCG_LOW_RATIO);
        mi->threshold[MEM_LEVEL_OOM] = (unsigned int)(mi->limit * MEMCG_MEDIUM_RATIO);
        mi->threshold_leave = (float)mi->limit * MEMCG_FOREGROUND_LEAVE_RATIO;
index 14f7174..6d6e628 100644 (file)
@@ -139,7 +139,7 @@ enum cgroup_memory_stat_id {
 
 struct mem_threshold {
        bool percent;
-       unsigned int threshold;
+       int threshold;                  /* MB or % */
 };
 
 struct mem_action {
@@ -148,12 +148,12 @@ struct mem_action {
 };
 
 struct memcg_conf {
-       struct mem_threshold threshold[MEM_LEVEL_MAX]; /* % or byte */
+       struct mem_threshold threshold[MEM_LEVEL_MAX];
        struct mem_action service;
        struct mem_action widget;
        struct mem_action guiapp;
        struct mem_action background;
-       unsigned int cgroup_limit[CGROUP_END];  /* % */
+       float cgroup_limit[CGROUP_END]; /* % */
        bool oom_popup;
 };
 
@@ -168,8 +168,8 @@ struct memcg_info {
        /* leave memory usage */
        unsigned int oomleave;
        /* thresholds, normal, swap, low, medium, and leave */
-       unsigned int threshold[MEM_LEVEL_MAX];
-       unsigned int threshold_leave;
+       unsigned int threshold[MEM_LEVEL_MAX];  /* MB */
+       unsigned int threshold_leave;                   /* MB */
        int evfd;
        int swappiness;
 };
index 1dcbd47..68c5089 100644 (file)
@@ -54,19 +54,19 @@ static int limiter_config(struct parse_result *result, void *user_data)
 
                if (!strncmp(result->name, VIP_GROUP_LIMIT_CONF,
                                        strlen(VIP_GROUP_LIMIT_CONF) + 1)) {
-                       memcg_conf->cgroup_limit[CGROUP_VIP] = atoi(result->value);
+                       memcg_conf->cgroup_limit[CGROUP_VIP] = atof(result->value);
                }
                else if (!strncmp(result->name, HIGH_GROUP_LIMIT_CONF,
                                        strlen(HIGH_GROUP_LIMIT_CONF) + 1)) {
-                       memcg_conf->cgroup_limit[CGROUP_HIGH] = atoi(result->value);
+                       memcg_conf->cgroup_limit[CGROUP_HIGH] = atof(result->value);
                }
                else if (!strncmp(result->name, MEDIUM_GROUP_LIMIT_CONF,
                                        strlen(MEDIUM_GROUP_LIMIT_CONF) + 1)) {
-                       memcg_conf->cgroup_limit[CGROUP_MEDIUM] = atoi(result->value);
+                       memcg_conf->cgroup_limit[CGROUP_MEDIUM] = atof(result->value);
                }
                else if (!strncmp(result->name, LOWEST_GROUP_LIMIT_CONF,
                                        strlen(LOWEST_GROUP_LIMIT_CONF) + 1)) {
-                       memcg_conf->cgroup_limit[CGROUP_LOW] = atoi(result->value);
+                       memcg_conf->cgroup_limit[CGROUP_LOW] = atof(result->value);
                }
                else {
                        _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
@@ -75,48 +75,8 @@ static int limiter_config(struct parse_result *result, void *user_data)
        }
        else if (!strncmp(result->section, MEMORY_LEVEL_THRESHOLD_SECTION,
                                strlen(MEMORY_LEVEL_THRESHOLD_SECTION)+1)) {
-               char temp = '\0';
-               int error = RESOURCED_ERROR_NONE;
-               bool percent;
-               char *ptr = strchr(result->value, '%');
-               if (ptr == NULL) {
-                       ptr = strchr(result->value, 'B');
-                       if (ptr == NULL) {
-                               _E("[DEBUG] Cannot find 'B' in the string (%s)", result->value);
-                               return RESOURCED_ERROR_FAIL;
-                       }
-
-                       if (result->value > (ptr - 1)) {
-                               _E("[DEBUG] Size of string should be larger than 1");
-                               return RESOURCED_ERROR_FAIL;
-                       }
 
-                       temp = *(ptr - 1);
-                       *(ptr - 1) = '\0';
-                       percent = false;
-               }
-               else { 
-                       *ptr = '\0';
-                       percent = true;
-               }
-               
-               if (!strncmp(result->name, MEDIUM_LEVEL_CONF,
-                                       strlen(MEDIUM_LEVEL_CONF) + 1)) {
-                       error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_MEDIUM, result->value);
-               }
-               else if (!strncmp(result->name, LOW_LEVEL_CONF,
-                                       strlen(LOW_LEVEL_CONF) + 1)) {
-                       error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_LOW, result->value);
-               }
-               else if (!strncmp(result->name, CRITICAL_LEVEL_CONF,
-                                       strlen(CRITICAL_LEVEL_CONF) + 1)) {
-                       error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_CRITICAL, result->value);
-               }
-               else if (!strncmp(result->name, OOM_LEVEL_CONF,
-                                       strlen(OOM_LEVEL_CONF) + 1)) {
-                       error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_OOM, result->value);
-               }
-               else if (!strncmp(result->name, OOM_POPUP_CONF,
+               if (!strncmp(result->name, OOM_POPUP_CONF,
                                        strlen(OOM_POPUP_CONF) + 1)) {
                        if (!strncmp(result->value, "yes", 4) ||
                                !strncmp(result->value, "1", 2) ||
@@ -131,11 +91,55 @@ static int limiter_config(struct parse_result *result, void *user_data)
                        }
                }
                else {
-                       _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
-                                       result->name, result->value, result->section);
-               }
+                       char temp = '\0';
+                       int error = RESOURCED_ERROR_NONE;
+                       bool percent;
+                       char *ptr = strchr(result->value, '%');
+                       if (ptr == NULL) {
+                               ptr = strchr(result->value, 'B');
+                               if (ptr == NULL) {
+                                       _E("[DEBUG] Cannot find 'B' in the string (%s)", result->value);
+                                       return RESOURCED_ERROR_FAIL;
+                               }
 
-               return error;
+                               if (result->value > (ptr - 1)) {
+                                       _E("[DEBUG] Size of string should be larger than 1");
+                                       return RESOURCED_ERROR_FAIL;
+                               }
+
+                               temp = *(ptr - 1);
+                               *(ptr - 1) = '\0';
+                               percent = false;
+                       }
+                       else { 
+                               *ptr = '\0';
+                               percent = true;
+                       }
+
+                       if (!strncmp(result->name, MEDIUM_LEVEL_CONF,
+                                               strlen(MEDIUM_LEVEL_CONF) + 1)) {
+                               error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_MEDIUM, result->value);
+                       }
+                       else if (!strncmp(result->name, LOW_LEVEL_CONF,
+                                               strlen(LOW_LEVEL_CONF) + 1)) {
+                               error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_LOW, result->value);
+                       }
+                       else if (!strncmp(result->name, CRITICAL_LEVEL_CONF,
+                                               strlen(CRITICAL_LEVEL_CONF) + 1)) {
+                               error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_CRITICAL, result->value);
+                       }
+                       else if (!strncmp(result->name, OOM_LEVEL_CONF,
+                                               strlen(OOM_LEVEL_CONF) + 1)) {
+                               error = set_memcg_conf_threshold(percent, temp, MEM_LEVEL_OOM, result->value);
+                       }
+
+                       else {
+                               _E("[DEBUG] Unknown configuration name (%s) and value (%s) on section (%s)",
+                                               result->name, result->value, result->section);
+                       }
+                       
+                       return error;
+               }
        }
        else if (!strncmp(result->section, MEMORY_APP_TYPE_LIMIT_SECTION,
                                strlen(MEMORY_APP_TYPE_LIMIT_SECTION)+1)) {
index 930de66..52d4759 100644 (file)
@@ -36,6 +36,8 @@ void add_module(const struct module_ops *module)
 {
        ret_msg_if(!module, "Invalid module handler\n");
 
+       _I("[DEBUG] module: %s is added", module->name);        
+
        if (module->priority == MODULE_PRIORITY_EARLY)
                modules_list = g_slist_prepend(modules_list, (gpointer)module);
        else
@@ -107,12 +109,12 @@ static void module_initcall_level(void *data, int priority)
                /* Module disabled on runtime or just failed to start. */
                if (ret < 0) {
                        module->initalized = MODULE_DROPPED;
-                       _E("Fail to initialize [%s] module, dropped.", module->name);
+                       _E("[DEBUG] Fail to initialize [%s] module, dropped.", module->name);
                        continue;
                }
 
                module->initalized = MODULE_INITIALIZED;
-               _D("Initialized [%s] module\n", module->name);
+               _D("[DEBUG] Initialized [%s] module\n", module->name);
        }
 }
 
index d293b70..8f4394b 100644 (file)
@@ -89,6 +89,7 @@ static inline void closedirp(DIR **d)
 #define MBYTE_TO_KBYTE(m) ((m) << 10)
 
 #define GBYTE_TO_BYTE(g) ((g) << 30)
+#define GBYTE_TO_MBYTE(g) ((g) << 10)
 
 #define streq(a, b) (strncmp((a), (b), strlen(b)+1) == 0)
 #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
index 5f420a8..1b96960 100644 (file)
@@ -9,12 +9,10 @@
 #include "cpu-hotplug.h"
 #include "proc-common.h"
 #include "file-helper.h"
+#include "cpu-cgroup.h"
 #include "util.h"
 
-#define CPU_SCHED_CONF_FILE     RD_CONFIG_FILE(limiter)
-#define CPU_SCHED_CONF_SECTION    "CPU-SCHED"
-#define CPU_SCHED_FG_NAME      "foreground"
-#define MOUNTS_PATH            "/proc/mounts"
+#define MOUNTS_PATH                    "/proc/mounts"
 #define CPUSET_CGROUP          "/sys/fs/cgroup/cpuset"
 
 
@@ -90,23 +88,23 @@ static int cpu_sched_init_cgroup_set(const struct coreset *set)
        assert(set);
        assert(set->name);
 
-       _D("cpu-sched: init cgroup set for %s", set->name);
+       _D("[DEBUG] cpu-sched: init cgroup set for %s", set->name);
        r = cgroup_make_subdir(CPUSET_CGROUP, set->name, NULL);
        if (r < 0) {
-               _E("failed to make cpuset cgroup (%s)", set->name);
+               _E("[DEBUG] failed to make cpuset cgroup (%s)", set->name);
                return r;
        }
 
        r = snprintf(buf, sizeof buf, "%s/%s", CPUSET_CGROUP, set->name);
        if (r < 0) {
-               _E("failed to setup memory nodes for cpuset (%s)", set->name);
+               _E("[DEBUG] failed to setup memory nodes for cpuset (%s)", set->name);
                return r;
        }
 
        /* don't force any memory nodes with this cpuset */
        r = cgroup_write_node_uint32(buf, "cpuset.mems", 0);
        ret_value_msg_if(r < 0, r,
-               "Failed to reset memory nodes for cpuset: %m");
+               "[DEBUG] Failed to reset memory nodes for cpuset: %m");
 
        return 0;
 }
@@ -118,7 +116,7 @@ static int cpu_sched_init_cgroup(struct cpu_sched *cs)
        GSList *i;
        struct coreset *c;
 
-       _D("cpu-sched: init cgroup subsystem");
+       _D("[DEBUG] cpu-sched: init cgroup subsystem");
        if (cpu_sched_is_cpuset_mounted() == false) {
                r = cgroup_make_subdir(CGROUP_PATH, "cpuset", NULL);
                if (r < 0) {
@@ -153,7 +151,7 @@ static int cpu_sched_new_core(struct coreset *set, int core_id)
        assert(set);
        assert(core_id >= 0);
 
-       _D("cpu-sched: new core %d for set %s", core_id, set->name);
+       _D("[DEBUG] cpu-sched: new core %d for set %s", core_id, set->name);
        c = (struct core *)calloc(1, sizeof *c);
        if (c == NULL) {
                _E("cpu-sched: could not allocate memory for core struct");
@@ -202,7 +200,7 @@ static int cpu_sched_parse_cpuset(struct coreset *set, char *value)
        assert(set);
        assert(value);
        assert(!set->cores);
-       _D("cpu-sched: parse cpuset for %s (%s)", set->name, value);
+       _D("[DEBUG] cpu-sched: parse cpuset for %s (%s)", set->name, value);
 
        ptr = strtok_r(value, ",", &saveptr);
        while (ptr) {
@@ -237,20 +235,18 @@ parse_cpuset_fail:
        return RESOURCED_ERROR_FAIL;
 }
 
-static int load_config(struct parse_result *result, void *user_data)
+static int load_config(struct cpu_sched *data)
 {
-       struct cpu_sched *data = (struct cpu_sched *)user_data;
+       char *name;
+       bool is_fg;
 
        assert(data);
 
-       if (strncmp(result->section, CPU_SCHED_CONF_SECTION, strlen(CPU_SCHED_CONF_SECTION)+1))
+       if (!get_cpucg_conf_name()) 
                return RESOURCED_ERROR_NONE;
 
-       bool is_fg = !strcmp(result->name, CPU_SCHED_FG_NAME);
-       char *name = strdup(result->name);
-
-       if (name == NULL)
-               return RESOURCED_ERROR_OUT_OF_MEMORY;
+       name = strdup(get_cpucg_conf_name());
+       is_fg = !strcmp(name, FOREGROUND_APPS);
 
        struct coreset *c = (struct coreset *)calloc(1, sizeof *c);
        if (c == NULL) {
@@ -260,8 +256,8 @@ static int load_config(struct parse_result *result, void *user_data)
 
        c->name = name;
 
-       if (cpu_sched_parse_cpuset(c, result->value) < 0) {
-               _E("cpu-sched parse %s coreset: could not parse", result->name);
+       if (cpu_sched_parse_cpuset(c, get_cpucg_conf_value()) < 0) {
+               _E("[DEBUG] cpu-sched parse %s coreset: could not parse", name);
                return RESOURCED_ERROR_FAIL;
        }
 
@@ -270,14 +266,16 @@ static int load_config(struct parse_result *result, void *user_data)
        else
                data->apps = g_slist_append(data->apps, c);
 
+       free_cpucg_conf();
        return RESOURCED_ERROR_NONE;
 }
 
 static int cpu_sched_parse_config(struct cpu_sched *data)
 {
-       _D("cpu-sched: parse config");
-       if (config_parse(CPU_SCHED_CONF_FILE, load_config, data) < 0)
-               return RESOURCED_ERROR_FAIL;
+       _D("[DEBUG] cpu-sched: parse config");
+       load_config(data);
+/*     if (config_parse(CPU_SCHED_CONF_FILE, load_config, data) < 0)
+               return RESOURCED_ERROR_FAIL;*/
 
        return RESOURCED_ERROR_NONE;
 }
@@ -571,7 +569,7 @@ static void cpu_sched_check_apps()
 static int cpu_sched_init(void *data)
 {
        int r;
-       _D("cpu-sched: init module");
+       _D("[DEBUG] cpu-sched: init module");
 
        if (cpu_sched_parse_config(&cs) != RESOURCED_ERROR_NONE) {
                _E("cpu-sched: error parsing config");
@@ -588,6 +586,7 @@ static int cpu_sched_init(void *data)
                return RESOURCED_ERROR_FAIL;
        }
 
+       _D("[DEBUG] cpu-sched: init module end");
        cs.is_initalized = true;
        cpu_sched_check_apps();
        return RESOURCED_ERROR_NONE;
index 02e5b89..e007bb1 100644 (file)
@@ -71,9 +71,12 @@ struct memory_limit_event {
 /**
  * @desc execute /usr/bin/memps and make log file with pid and process name
  */
-void make_memps_log(enum mem_log path, pid_t pid, char *victim_name);
-
+//void make_memps_log(enum mem_log path, pid_t pid, char *victim_name);
 
+void lowmem_memory_init(unsigned int service_limit, unsigned int widget_limit,
+               unsigned int guiapp_limit, unsigned int bgapp_limit);
+void lowmem_action_init(int service_action, int widget_action,
+               int guiapp_action, int bgapp_action);
 int lowmem_limit_set_app(unsigned int limit, struct proc_app_info *pai,
                enum proc_action action);
 void lowmem_limit_set_system_service(pid_t pid, unsigned int limit,
index d07a146..502fb6f 100644 (file)
@@ -77,11 +77,15 @@ static enum mem_limit_type mem_limit;
 
 static GHashTable *memory_limit_hash;
 static char *registerpath;
-static int mem_service_limit;
-static int mem_guiapp_limit;
-static int mem_widget_limit;
-static int mem_bgapp_limit;
+static unsigned int mem_service_limit;
+static unsigned int mem_widget_limit;
+static unsigned int mem_guiapp_limit;
+static unsigned int mem_bgapp_limit;
 
+static int mem_service_action;
+static int mem_widget_action;
+static int mem_guiapp_action;
+static int mem_bgapp_action;
 
 struct memory_info {
        pid_t pid;
@@ -423,9 +427,8 @@ int lowmem_limit_move_cgroup(struct proc_app_info *pai)
        return RESOURCED_ERROR_NONE;
 }
 
-static int memlimit_config_parse(struct parse_result *result, void *user_data)
+/*static int memlimit_config_parse(struct parse_result *result, void *user_data)
 {
-       /* Single config section is expected */
        if (!result->section)
                return RESOURCED_ERROR_NONE;
 
@@ -449,7 +452,7 @@ static int memlimit_config_parse(struct parse_result *result, void *user_data)
        }
 
        return RESOURCED_ERROR_NONE;
-}
+}*/
 
 void lowmem_limit_set_system_service(pid_t pid, unsigned int limit,
                const char *name, enum proc_action action)
@@ -505,7 +508,7 @@ int lowmem_limit_set_app(unsigned int limit, struct proc_app_info *pai,
        unsigned int totalram = lowmem_get_totalram();
 
        if (limit < MIN_LIMIT_VALUE || limit > totalram) {
-               _E("It's meaningless to set memory limit with size (%d)", limit);
+               _E("[DEBUG] It's meaningless to set memory limit with size (%d)", limit);
                return RESOURCED_ERROR_INVALID_PARAMETER;
        }
 
@@ -582,7 +585,7 @@ static int lowmem_limit_service(void *data)
                return RESOURCED_ERROR_NONE;
 
        if (mem_service_limit) {
-               lowmem_limit_set_app(MBYTE_TO_BYTE(mem_service_limit), ps->pai, PROC_ACTION_KILL);
+               lowmem_limit_set_app(mem_service_limit, ps->pai, mem_service_action);
        }
        return RESOURCED_ERROR_NONE;
 }
@@ -597,10 +600,10 @@ static int lowmem_limit_appwidget(void *data)
                return RESOURCED_ERROR_NONE;
 
        if (mem_guiapp_limit && ps->pai->type == PROC_TYPE_GUI) {
-               lowmem_limit_set_app(MBYTE_TO_BYTE(mem_guiapp_limit), ps->pai, PROC_ACTION_KILL);
+               lowmem_limit_set_app(mem_guiapp_limit, ps->pai, mem_guiapp_action);
        }
        if (mem_widget_limit && ps->pai->type == PROC_TYPE_WIDGET) {
-               lowmem_limit_set_app(MBYTE_TO_BYTE(mem_widget_limit), ps->pai, PROC_ACTION_KILL);
+               lowmem_limit_set_app(mem_widget_limit, ps->pai, mem_widget_action);
        }
 
        return RESOURCED_ERROR_NONE;
@@ -615,7 +618,7 @@ static int lowmem_limit_bgapp(void *data)
        if (ps->pai && ps->pai->memory.memlimit_update_exclude)
                return RESOURCED_ERROR_NONE;
 
-       lowmem_limit_set_app(MBYTE_TO_BYTE(mem_bgapp_limit), ps->pai, PROC_ACTION_KILL);
+       lowmem_limit_set_app(mem_bgapp_limit, ps->pai, mem_bgapp_action);
 
        return RESOURCED_ERROR_NONE;
 }
@@ -634,6 +637,31 @@ static int lowmem_limit_fgapp(void *data)
 
        return RESOURCED_ERROR_NONE;
 }
+
+void lowmem_memory_init(unsigned int service_limit, unsigned int widget_limit,
+               unsigned int guiapp_limit, unsigned int bgapp_limit)
+{
+       mem_service_limit = service_limit;
+       mem_widget_limit = widget_limit;
+       mem_guiapp_limit = guiapp_limit;
+       mem_bgapp_limit = bgapp_limit;
+
+       _I("[DEBUG] Limit of service = %u, widget = %u, guiap = %u, bgapp = %u bytes", 
+                       mem_service_limit, mem_widget_limit, mem_guiapp_limit, mem_bgapp_limit);
+}
+
+void lowmem_action_init(int service_action, int widget_action,
+               int guiapp_action, int bgapp_action)
+{
+       mem_service_action = service_action;
+       mem_widget_action = widget_action;
+       mem_guiapp_action = guiapp_action;
+       mem_bgapp_action = bgapp_action;
+
+       _I("[DEBUG] action of service = %d, widget = %d, guiap = %d, bgapp = %d bytes", 
+                       service_action, widget_action, guiapp_action, bgapp_action);
+}
+
 void lowmem_limit_init(void)
 {
        int result;
@@ -646,11 +674,6 @@ void lowmem_limit_init(void)
        else
                registerpath = MEMCG_USAGE;
 
-
-       /* Load configuration */
-       config_parse(MEM_CONF_FILE, memlimit_config_parse,
-                       NULL);
-
        register_notifier(RESOURCED_NOTIFIER_LIMIT_SYSTEM_SERVICE, lowmem_limit_system_service);
        register_notifier(RESOURCED_NOTIFIER_LIMIT_APP, lowmem_limit_app);
        if (mem_limit == MEM_LIMIT_NONE)
index 5b5d297..94271dd 100644 (file)
@@ -228,13 +228,13 @@ struct lowmem_worker {
 
 static struct lowmem_worker lmw;
 
-static int memlog_enabled;
-static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
+//static int memlog_enabled;
+//static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
 /* remove logfiles to reduce to this threshold.
  * it is about five-sixths of the memlog_nr_max. */
-static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
-static char *memlog_path = DEFAULT_MEMLOG_PATH;
-static char *memlog_prefix[MEMLOG_MAX];
+//static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
+//static char *memlog_path = DEFAULT_MEMLOG_PATH;
+//static char *memlog_prefix[MEMLOG_MAX];
 
 #define LOWMEM_WORKER_IS_ACTIVE(_lmw)  g_atomic_int_get(&(_lmw)->active)
 #define LOWMEM_WORKER_ACTIVATE(_lmw)   g_atomic_int_set(&(_lmw)->active, 1)
@@ -387,8 +387,8 @@ static const char *convert_status_to_str(int status)
 
 static const char *convert_memstate_to_str(int mem_state)
 {
-       static const char *state_table[] = {"mem normal", "mem dedup", "mem swap", "mem low",
-                       "mem medium"};
+       static const char *state_table[] = {"mem high", "mem medium",
+               "mem low", "mem critical", "mem oom",};
        if (mem_state >= 0 && mem_state < MEM_LEVEL_MAX)
                return state_table[mem_state];
        return "";
@@ -486,7 +486,7 @@ unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
        return total_size;
 }
 
-static int memps_file_select(const struct dirent *entry)
+/*static int memps_file_select(const struct dirent *entry)
 {
        return strstr(entry->d_name, "memps") ? 1 : 0;
 }
@@ -630,9 +630,8 @@ void make_memps_log(enum mem_log memlog, pid_t pid, char *victim_name)
                exec_cmd(ARRAY_SIZE(argv), argv);
        }
 
-       /* best effort to limit the number of logfiles up to memlog_nr_max */
        clear_logs(memlog_path);
-}
+}*/
 
 static int lowmem_kill_victim(const struct task_info *tsk,
                int flags, int memps_log, unsigned int *victim_size)
@@ -659,8 +658,8 @@ static int lowmem_kill_victim(const struct task_info *tsk,
                return RESOURCED_ERROR_FAIL;
        }
 
-       if (!memps_log)
-               make_memps_log(MEMLOG_MEMPS, pid, appname);
+/*     if (!memps_log)
+               make_memps_log(MEMLOG_MEMPS, pid, appname);*/
 
        pai = tsk->pai;
        if (pai) {
@@ -697,8 +696,8 @@ static int lowmem_kill_victim(const struct task_info *tsk,
                lowmem_launch_oompopup();
                oom_popup = true;
        }
-       if (memps_log)
-               make_memps_log(MEMLOG_MEMPS, pid, appname);
+/*     if (memps_log)
+               make_memps_log(MEMLOG_MEMPS, pid, appname);*/
 
        return RESOURCED_ERROR_NONE;
 }
@@ -1108,8 +1107,8 @@ done:
                count, total_size, reclaim_size, shortfall, convert_status_to_str(status));
 
        /* After we finish reclaiming it's worth to remove oldest memps logs */
-       if (count && memlog_enabled)
-               request_helper_worker(CLEAR_LOGS, memlog_path, clear_logs, NULL);
+/*     if (count && memlog_enabled)
+               request_helper_worker(CLEAR_LOGS, memlog_path, clear_logs, NULL);*/
        ctl->status = status;
 }
 
@@ -1505,7 +1504,7 @@ static unsigned int check_mem_state(unsigned int available)
        return mem_state;
 }
 
-static int load_bg_reclaim_config(struct parse_result *result, void *user_data)
+/*static int load_bg_reclaim_config(struct parse_result *result, void *user_data)
 {
        if (!result)
                return RESOURCED_ERROR_INVALID_PARAMETER;
@@ -1622,10 +1621,6 @@ static int set_memory_config(struct parse_result *result, void *user_data)
        } else if (!strncmp(result->name, "NumMaxVictims", strlen("NumMaxVictims")+1)) {
                int value = atoi(result->value);
                num_max_victims = value;
-               /*
-                * calculate the number of victims to be killed between memory checks.
-                * this value depends on the number of max victims
-                */
                num_vict_between_check = value > MAX_MEMORY_CGROUP_VICTIMS/2
                                                ? 3 : value > MAX_MEMORY_CGROUP_VICTIMS/4
                                                                ? 2 : 1;
@@ -1658,7 +1653,7 @@ static int set_memory_config(struct parse_result *result, void *user_data)
        }
 
        return RESOURCED_ERROR_NONE;
-}
+}*/
 
 /* setup memcg parameters depending on total ram size. */
 static void setup_memcg_params(void)
@@ -2162,46 +2157,72 @@ static int lowmem_bg_reclaim_handler(void *data)
        return RESOURCED_ERROR_NONE;
 }
 
+static int calculate_threshold_size(double ratio)
+{
+       int size = (double)totalram * ratio / 100.0;
+       return size;
+}
+
 static void load_configs(const char *path)
 {
-       if (config_parse(path, set_memory_config, NULL))
-               _E("(%s-mem) parse Fail", path);
+       struct memcg_conf *memcg_conf = get_memcg_conf();
 
-       if (config_parse(path, load_popup_config, NULL))
-               _E("(%s-popup) parse Fail", path);
+       /* set MemoryGroupLimit section */
+       for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) { 
+               memcg_info_set_limit(get_memcg_info(cgroup),
+                               memcg_conf->cgroup_limit[cgroup]/100.0, totalram);
+       }
+
+       /* set MemoryLevelThreshold section */
+       for (int lvl = MEM_LEVEL_MEDIUM; lvl < MEM_LEVEL_MAX; lvl++) {
+               if (memcg_conf->threshold[lvl].percent)
+                       memcg_set_threshold(CGROUP_ROOT, lvl,
+                                       calculate_threshold_size(memcg_conf->threshold[lvl].threshold));
+               else
+                       memcg_set_threshold(CGROUP_ROOT, lvl,
+                                       memcg_conf->threshold[lvl].threshold);
+       }
+       oom_popup_enable = memcg_conf->oom_popup;
 
-       if (config_parse(path, load_bg_reclaim_config, NULL))
-               _E("(%s-bg-reclaim) parse Fail", path);
+       /* set MemoryAppTypeLimit and MemoryAppStatusLimit section */
+       lowmem_memory_init(memcg_conf->service.memory, memcg_conf->widget.memory,
+                       memcg_conf->guiapp.memory, memcg_conf->background.memory);
+       lowmem_action_init(memcg_conf->service.action, memcg_conf->widget.action,
+                       memcg_conf->guiapp.action, memcg_conf->background.action);
 
-       if (config_parse(path, load_mem_log_config, NULL))
-               _E("(%s-mem-log) parse Fail", path);
+       free_memcg_conf();
 }
 
 static void print_mem_configs(void)
 {
        /* print info of Memory section */
+       for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
+               _I("[DEBUG] set memory for cgroup '%s' to %u bytes",
+                               convert_cgroup_type_to_str(cgroup), get_memcg_info(cgroup)->limit);     
+       }
+
        for (int mem_lvl = 0; mem_lvl < MEM_LEVEL_MAX; mem_lvl++)
-               _I("set threshold for state '%s' to %u MB",
-               convert_memstate_to_str(mem_lvl), get_root_memcg_info()->threshold[mem_lvl]);
+               _I("[DEBUG] set threshold for memory level '%s' to %u MB",
+                               convert_memstate_to_str(mem_lvl), get_root_memcg_info()->threshold[mem_lvl]);
 
-       _I("set number of max victims as %d", num_max_victims);
-       _I("set threshold leave to %u MB", get_root_memcg_info()->threshold_leave);
-       _I("set proactive threshold to %u MB", proactive_threshold);
-       _I("set proactive low memory killer leave to %u MB", proactive_leave);
+       _I("[DEBUG] set number of max victims as %d", num_max_victims);
+       _I("[DEBUG] set threshold leave to %u MB", get_root_memcg_info()->threshold_leave);
+       _I("[DEBUG] set proactive threshold to %u MB", proactive_threshold);
+       _I("[DEUBG] set proactive low memory killer leave to %u MB", proactive_leave);
 
        /* print info of POPUP section */
-       _I("oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
+       _I("[DEBUG] oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
 
        /* print info of BackgroundReclaim section */
-       _I("Background reclaim is %s", bg_reclaim == true ? "enabled" : "disabled");
+       _I("[DEBUG] Background reclaim is %s", bg_reclaim == true ? "enabled" : "disabled");
 
        /* print info of Logging section */
-       _I("memory logging is %s", memlog_enabled == 1 ? "enabled" : "disabled");
+/*     _I("memory logging is %s", memlog_enabled == 1 ? "enabled" : "disabled");
        _I("memory logging path is %s", memlog_path);
        _I("the max number of memory logging is %d", memlog_nr_max);
        _I("the batch threshold of memory log is %d", memlog_remove_batch_thres);
        _I("prefix of memps is %s", memlog_prefix[MEMLOG_MEMPS]);
-       _I("prefix of memlimit memps is %s", memlog_prefix[MEMLOG_MEMPS_MEMLIMIT]);
+       _I("prefix of memlimit memps is %s", memlog_prefix[MEMLOG_MEMPS_MEMLIMIT]);*/
 }
 
 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
@@ -2209,7 +2230,7 @@ static int lowmem_init(void)
 {
        int ret = RESOURCED_ERROR_NONE;
 
-       _D("resourced memory init start");
+       _D("[DEBUG] resourced memory init start");
 
        /* init memcg */
        ret = cgroup_make_full_subdir(MEMCG_PATH);
@@ -2228,14 +2249,14 @@ static int lowmem_init(void)
        /* make a worker thread called low memory killer */
        ret = lowmem_activate_worker();
        if (ret) {
-               _E("oom thread create failed\n");
+               _E("[DEBUG] oom thread create failed\n");
                return ret;
        }
 
        /* register threshold and event fd */
        ret = lowmem_press_setup_eventfd();
        if (ret) {
-               _E("eventfd setup failed");
+               _E("[DEBUG] eventfd setup failed");
                return ret;
        }
 
@@ -2243,6 +2264,7 @@ static int lowmem_init(void)
        lowmem_limit_init();
        lowmem_system_init();
 
+       _D("[DEBUG] resourced memory init end with ret = %d", ret);
        register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
        register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
        register_notifier(RESOURCED_NOTIFIER_LCD_OFF, lowmem_bg_reclaim_handler);