tizen 2.3 release
[kernel/api/system-resource.git] / src / memory / vmpressure-lowmem-handler.c
index fb0d69f..0c0db5c 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 #include <stdio.h>
-#include <stdbool.h>
 #include <fcntl.h>
 #include <assert.h>
 #include <limits.h>
@@ -34,7 +33,6 @@
 #include <unistd.h>
 #include <time.h>
 #include <limits.h>
-#include <fcntl.h>
 #include <dirent.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/eventfd.h>
 #include <sys/sysinfo.h>
 #include <Ecore.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 
 #include "trace.h"
+#include "cgroup.h"
 #include "proc-main.h"
 #include "lowmem-handler.h"
 #include "proc-process.h"
+#include "swap-common.h"
 #include "lowmem-common.h"
 #include "resourced.h"
 #include "macro.h"
+#include "notifier.h"
 #include "config-parser.h"
 #include "module.h"
+#include "logging-common.h"
 
 #define MEMINFO_PATH                   "/proc/meminfo"
 #define MEMCG_PATH                     "/sys/fs/cgroup"
-#define MEMPS_LOG_FILE                 "/var/log/memps"
+#define MEMPS_LOG_PATH                 "/var/log/"
+#define MEMPS_LOG_FILE                 MEMPS_LOG_PATH"memps"
 #define MEMPS_EXEC_PATH                        "usr/bin/memps"
 #define MEMCG_MOVE_CHARGE_PATH         "memory.move_charge_at_immigrate"
 #define MEMCG_OOM_CONTROL_PATH         "memory.oom_control"
 #define MAX_MEMORY_CGROUP_VICTIMS      10
 #define MAX_CGROUP_VICTIMS             1
 #define OOM_TIMER_INTERVAL             2
-#define MAX_TIMER_CHECK                10
-#define OOM_MULTIKILL_WAIT             (1000*1000)
+#define OOM_MULTIKILL_WAIT             (500*1000)
+#define OOM_SIGKILL_WAIT               1
 #define OOM_SCORE_POINT_WEIGHT         1500
+#define OOM_KILLER_PRIORITY            -20
 #define MAX_FD_VICTIMS                 10
+#define MAX_SWAP_VICTIMS               5
+#define MAX_MEMPS_LOGS                 50
+#define NUM_RM_LOGS                    5
+#define THRESHOLD_MARGIN               10 /* MB */
 
 #define MEM_SIZE_64                    64  /* MB */
 #define MEM_SIZE_256                   256 /* MB */
 #define MEM_SIZE_2048                  2048 /* MB */
 
 /* thresholds for 64M RAM*/
-#define MEMCG_MEMORY_64_THRES_LOW              8 /* MB */
-#define MEMCG_MEMORY_64_THRES_MEDIUM           5 /* MB */
-#define MEMCG_MEMORY_64_THRES_LEAVE            8 /* MB */
+#define DYNAMIC_PROCESS_64_THRES               10 /* MB */
+#define DYNAMIC_PROCESS_64_LEAVE               30 /* MB */
+#define MEMCG_MEMORY_64_THRES_SWAP             15 /* MB */
+#define MEMCG_MEMORY_64_THRES_LOW              8  /* MB */
+#define MEMCG_MEMORY_64_THRES_MEDIUM           5  /* MB */
+#define MEMCG_MEMORY_64_THRES_LEAVE            8  /* MB */
 
 /* thresholds for 256M RAM */
+#define DYNAMIC_PROCESS_256_THRES              50 /* MB */
+#define DYNAMIC_PROCESS_256_LEAVE              80 /* MB */
+#define MEMCG_MEMORY_256_THRES_SWAP            40 /* MB */
 #define MEMCG_MEMORY_256_THRES_LOW             20 /* MB */
 #define MEMCG_MEMORY_256_THRES_MEDIUM          10 /* MB */
 #define MEMCG_MEMORY_256_THRES_LEAVE           20 /* MB */
 
 /* threshold for 512M RAM */
-#define MEMCG_MEMORY_512_THRES_LOW             50 /* MB */
-#define MEMCG_MEMORY_512_THRES_MEDIUM          40 /* MB */
-#define MEMCG_MEMORY_512_THRES_LEAVE           60 /* MB */
+#define DYNAMIC_PROCESS_512_THRES              80 /* MB */
+#define DYNAMIC_PROCESS_512_LEAVE              100 /* MB */
+#define DYNAMIC_PROCESS_512_THRESLAUNCH        60 /* MB */
+#define DYNAMIC_PROCESS_512_LEAVELAUNCH        80 /* MB */
+#define MEMCG_MEMORY_512_THRES_SWAP            100 /* MB */
+#define MEMCG_MEMORY_512_THRES_LOW             50  /* MB */
+#define MEMCG_MEMORY_512_THRES_MEDIUM          40  /* MB */
+#define MEMCG_MEMORY_512_THRES_LEAVE           60  /* MB */
 
 /* threshold for more than 1024M RAM */
+#define DYNAMIC_PROCESS_1024_THRES             150 /* MB */
+#define DYNAMIC_PROCESS_1024_LEAVE             300 /* MB */
+#define MEMCG_MEMORY_1024_THRES_SWAP           300 /* MB */
 #define MEMCG_MEMORY_1024_THRES_LOW            200 /* MB */
 #define MEMCG_MEMORY_1024_THRES_MEDIUM         100 /* MB */
 #define MEMCG_MEMORY_1024_THRES_LEAVE          150 /* MB */
 
 /* threshold for more than 2048M RAM */
+#define DYNAMIC_PROCESS_2048_THRES             200 /* MB */
+#define DYNAMIC_PROCESS_2048_LEAVE             500 /* MB */
+#define MEMCG_MEMORY_2048_THRES_SWAP           300 /* MB */
 #define MEMCG_MEMORY_2048_THRES_LOW            200 /* MB */
 #define MEMCG_MEMORY_2048_THRES_MEDIUM         160 /* MB */
 #define MEMCG_MEMORY_2048_THRES_LEAVE          300 /* MB */
 
-enum {
-       MEMNOTIFY_NORMAL,
-       MEMNOTIFY_LOW,
-       MEMNOTIFY_MEDIUM,
-       MEMNOTIFY_MAX_LEVELS,
-};
-
 static int thresholds[MEMNOTIFY_MAX_LEVELS];
+static int dynamic_process_threshold[DYNAMIC_KILL_MAX];
+static int dynamic_process_leave[DYNAMIC_KILL_MAX];
 
 struct task_info {
        pid_t pid;
@@ -160,9 +182,10 @@ struct lowmem_process_entry {
        void (*action) (void);
 };
 
-struct mem_info {
-       unsigned real_free;
-       unsigned reclaimable;
+
+struct victims {
+       int num;
+       pid_t pids[MAX_MEMORY_CGROUP_VICTIMS];
 };
 
 /* low memory action function for cgroup */
@@ -172,6 +195,7 @@ static int compare_bg_victims(const struct task_info *ta, const struct task_info
 static int compare_fg_victims(const struct task_info *ta, const struct task_info *tb);
 /* low memory action function */
 static void normal_act(void);
+static void swap_act(void);
 static void low_act(void);
 static void medium_act(void);
 
@@ -181,10 +205,16 @@ static Eina_Bool medium_cb(void *data);
        { MEMNOTIFY_##c, MEMNOTIFY_##n, act}
 
 static struct lowmem_process_entry lpe[] = {
+       LOWMEM_ENTRY(NORMAL,    SWAP,           swap_act),
        LOWMEM_ENTRY(NORMAL,    LOW,            low_act),
        LOWMEM_ENTRY(NORMAL,    MEDIUM,         medium_act),
+       LOWMEM_ENTRY(SWAP,      NORMAL,         normal_act),
+       LOWMEM_ENTRY(SWAP,      LOW,            low_act),
+       LOWMEM_ENTRY(SWAP,      MEDIUM,         medium_act),
+       LOWMEM_ENTRY(LOW,       SWAP,           swap_act),
        LOWMEM_ENTRY(LOW,       NORMAL,         normal_act),
        LOWMEM_ENTRY(LOW,       MEDIUM,         medium_act),
+       LOWMEM_ENTRY(MEDIUM,    SWAP,           swap_act),
        LOWMEM_ENTRY(MEDIUM,    NORMAL,         normal_act),
        LOWMEM_ENTRY(MEDIUM,    LOW,            low_act),
 };
@@ -220,7 +250,10 @@ static struct memcg_class memcg_class[MEMCG_MAX_GROUPS] = {
 static int evfd[MEMCG_MAX_GROUPS] = {-1, };
 static int cur_mem_state = MEMNOTIFY_NORMAL;
 static Ecore_Timer *oom_check_timer = NULL;
+static Ecore_Timer *oom_sigkill_timer = NULL;
 static pid_t killed_fg_victim;
+static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
+struct victims killed_tasks = {0, {0, }};
 
 static pthread_t       oom_thread      = 0;
 static pthread_mutex_t oom_mutex       = PTHREAD_MUTEX_INITIALIZER;
@@ -228,6 +261,10 @@ static pthread_cond_t      oom_cond        = PTHREAD_COND_INITIALIZER;
 
 static unsigned long totalram;
 static unsigned long ktotalram;
+
+static const struct module_ops memory_modules_ops;
+static const struct module_ops *lowmem_ops;
+
 static inline void get_total_memory(void)
 {
        struct sysinfo si;
@@ -240,18 +277,19 @@ static inline void get_total_memory(void)
        }
 }
 
-static void get_mem_info(struct mem_info *mi)
+unsigned int get_available(void)
 {
        char buf[PATH_MAX];
        FILE *fp;
        char *idx;
-       unsigned int tfree = 0, tactive_file = 0, tinactive_file = 0;
+       unsigned int free = 0, cached = 0;
+       unsigned int available = 0;
 
        fp = fopen(MEMINFO_PATH, "r");
 
        if (!fp) {
                _E("%s open failed, %d", buf, fp);
-               return;
+               return available;
        }
 
        while (fgets(buf, PATH_MAX, fp) != NULL) {
@@ -259,27 +297,28 @@ static void get_mem_info(struct mem_info *mi)
                        idx += strlen("MemFree:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tfree = atoi(idx);
-                       tfree >>= 10;
-               } else if((idx = strstr(buf, "Active(file):"))) {
-                       idx += strlen("Active(file):");
+                       free = atoi(idx);
+               } else if ((idx = strstr(buf, "MemAvailable:"))) {
+                       idx += strlen("MemAvailable:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tactive_file = atoi(idx);
-                       tactive_file >>= 10;
-               } else if((idx = strstr(buf, "Inactive(file):"))) {
-                       idx += strlen("Inactive(file):");
+                       available = atoi(idx);
+                       break;
+               } else if((idx = strstr(buf, "Cached:"))) {
+                       idx += strlen("Cached:");
                        while (*idx < '0' || *idx > '9')
                                idx++;
-                       tinactive_file = atoi(idx);
-                       tinactive_file >>= 10;
+                       cached = atoi(idx);
                        break;
                }
        }
 
-       mi->real_free = tfree;
-       mi->reclaimable = tactive_file + tinactive_file;
+       if (available == 0)
+               available = free + cached;
+       available >>= 10;
        fclose(fp);
+
+       return available;
 }
 
 static bool get_mem_usage_by_pid(pid_t pid, unsigned int *rss)
@@ -361,36 +400,56 @@ static int get_mem_usage_anon(int idx, unsigned int *result)
        return RESOURCED_ERROR_NONE;
 }
 
-static int remove_shm(void)
+static int memps_file_select(const struct dirent *entry)
 {
-       int maxid, shmid, id;
-       struct shmid_ds shmseg;
-       struct shm_info shm_info;
+   return (strstr(entry->d_name, "memps") ? 1 : 0);
+}
 
-       maxid = shmctl(0, SHM_INFO, (struct shmid_ds *)(void *)&shm_info);
-       if (maxid < 0) {
-               _E("shared mem error\n");
-               return RESOURCED_ERROR_FAIL;
+int compare_func(const struct dirent **a, const struct dirent **b)
+{
+       const char *fn_a = (*a)->d_name;
+       const char *fn_b = (*b)->d_name;
+       char *str_at = strrchr(fn_a, '_') + 1;
+       char *str_bt = strrchr(fn_b, '_') + 1;
+
+       return strcmp(str_at, str_bt);
+}
+
+static void clear_logs(char *dir)
+{
+       struct dirent **namelist;
+       int n, i, ret;
+       char fname[BUF_MAX];
+
+       n = scandir(dir, &namelist, memps_file_select, compare_func);
+       _D("num of log files %d", n);
+       if (n < MAX_MEMPS_LOGS) {
+               while (n--)
+                       free(namelist[n]);
+               free(namelist);
+               return;
        }
 
-       for (id = 0; id <= maxid; id++) {
-               shmid = shmctl(id, SHM_STAT, &shmseg);
-               if (shmid < 0)
-                       continue;
-               if (shmseg.shm_nattch == 0) {
-                       _D("shared memory killer ==> %d killed\n",
-                                 shmid);
-                       shmctl(shmid, IPC_RMID, NULL);
+       for (i = 0; i < n; i++) {
+               if (i < NUM_RM_LOGS) {
+                       strcpy(fname, dir);
+                       strcat(fname, namelist[i]->d_name);
+                       _D("remove log file %s", fname);
+                       ret = remove(fname);
+                       if (ret < 0)
+                               _E("%s file cannot removed", fname);
                }
+
+               free(namelist[i]);
        }
-       return 0;
+       free(namelist);
 }
 
 static void make_memps_log(char *file, pid_t pid, char *victim_name)
 {
        time_t now;
-       struct tm *cur_tm;
-       char new_log[512];
+       struct tm cur_tm;
+       char new_log[BUF_MAX];
        static pid_t old_pid;
 
        if (old_pid == pid)
@@ -398,27 +457,20 @@ static void make_memps_log(char *file, pid_t pid, char *victim_name)
        old_pid = pid;
 
        now = time(NULL);
-       cur_tm = (struct tm *)malloc(sizeof(struct tm));
-       if (cur_tm == NULL) {
-               _E("Fail to memory allocation");
-               return;
-       }
 
-       if (localtime_r(&now, cur_tm) == NULL) {
+       if (localtime_r(&now, &cur_tm) == NULL) {
                _E("Fail to get localtime");
-               free(cur_tm);
                return;
        }
 
        snprintf(new_log, sizeof(new_log),
-                "%s_%s_%d_%.4d%.2d%.2d_%.2d%.2d%.2d.log", file, 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);
+                "%s_%s_%d_%.4d%.2d%.2d%.2d%.2d%.2d", file, 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);
 
-       free(cur_tm);
        if (fork() == 0) {
-               execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-f", new_log, (char *)NULL);
+               execl(MEMPS_EXEC_PATH, MEMPS_EXEC_PATH, "-r", new_log, (char *)NULL);
                exit(0);
        }
 }
@@ -437,11 +489,11 @@ static int lowmem_check_current_state(int memcg_index)
        }
 
        if (oomleave > usage) {
-               _D("%s : usage : %u, oomleave : %u",
+               _D("%s : usage : %u, leave threshold : %u",
                                __func__, usage, oomleave);
                return RESOURCED_ERROR_NONE;
        } else {
-               _D("%s : usage : %u, oomleave : %u",
+               _D("%s : usage : %u, leave threshold: %u",
                                __func__, usage, oomleave);
                return RESOURCED_ERROR_FAIL;
        }
@@ -490,15 +542,14 @@ static int compare_fg_victims(const struct task_info *ta, const struct task_info
        return ((int)(tb->size) - (int)(ta->size));
 }
 
-static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct task_info *selected,
-                                       unsigned *total_size, unsigned
-                                       should_be_freed, int force)
+static int lowmem_get_cgroup_victims(int idx, int max_victims, struct task_info *selected,
+       unsigned should_be_freed, int flags)
 {
        FILE *f = NULL;
        char buf[LOWMEM_PATH_MAX] = {0, };
        int i = 0;
-       int sel = nsel;
-       unsigned total_victim_size = *total_size;
+       int num_victims = 0;
+       unsigned total_victim_size = 0;
        char appname[PATH_MAX] = {0, };
 
        GArray *victim_candidates = NULL;
@@ -507,7 +558,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
 
        /* if g_array_new fails, return the current number of victims */
        if (victim_candidates == NULL)
-               return sel;
+               return num_victims;
 
        if (idx == MEMCG_MEMORY) {
                sprintf(buf, "%s/%s/system.slice/cgroup.procs",
@@ -526,7 +577,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
                         * if task read in this cgroup fails,
                         * return the current number of victims
                         */
-                       return sel;
+                       return num_victims;
                }
        }
 
@@ -552,15 +603,13 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
                        continue;
 
                for (i = 0; i < victim_candidates->len; i++) {
-                       struct task_info tsk = g_array_index(victim_candidates,
+                       struct task_info *tsk = &g_array_index(victim_candidates,
                                                        struct task_info, i);
-                       if (getpgid(tpid) == tsk.pgid) {
-                               tsk.size += tsize;
-                               if (tsk.oom_score_adj < 0 && toom > 0) {
-                                       tsk.pid = tpid;
-                                       tsk.oom_score_adj = toom;
-                                       g_array_remove_index(victim_candidates, i);
-                                       g_array_append_val(victim_candidates, tsk);
+                       if (getpgid(tpid) == tsk->pgid) {
+                               tsk->size += tsize;
+                               if (tsk->oom_score_adj <= 0 && toom > 0) {
+                                       tsk->pid = tpid;
+                                       tsk->oom_score_adj = toom;
                                }
                                break;
                        }
@@ -583,7 +632,7 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
        if (victim_candidates->len == 0) {
                g_array_free(victim_candidates, true);
                fclose(f);
-               return sel;
+               return num_victims;
        }
 
        g_array_sort(victim_candidates,
@@ -591,103 +640,217 @@ static int lowmem_get_cgroup_victims(int idx, int nsel, int max_victims, struct
 
        for (i = 0; i < victim_candidates->len; i++) {
                struct task_info tsk;
-               if (sel >= max_victims ||
-                       (!force && total_victim_size >= should_be_freed)) {
+               if (num_victims >= max_victims ||
+                   (!(flags & OOM_NOMEMORY_CHECK) &&
+                       total_victim_size >= should_be_freed)) {
                        break;
                }
+
                tsk = g_array_index(victim_candidates, struct task_info, i);
 
-               selected[sel].pid = tsk.pid;
-               selected[sel].pgid = tsk.pgid;
-               selected[sel].oom_score_adj = tsk.oom_score_adj;
-               selected[sel].size = tsk.size;
-               total_victim_size += tsk.size >> 10;
-               sel++;
+               if (tsk.oom_score_adj < OOMADJ_BACKGRD_UNLOCKED) {
+                       unsigned int available;
+                       if ((flags & OOM_FORCE) || !(flags & OOM_TIMER_CHECK)) {
+                               _D("%d is skipped during force kill", tsk.pid);
+                               break;
+                       }
+                       available = get_available();
+                       if ((flags & OOM_TIMER_CHECK) &&
+                           (available > thresholds[MEMNOTIFY_MEDIUM] +
+                               THRESHOLD_MARGIN)) {
+                               _D("available: %d MB, larger than threshold margin",
+                                       available);
+                               break;
+                       }
+               }
 
+               selected[num_victims].pid = tsk.pid;
+               selected[num_victims].pgid = tsk.pgid;
+               selected[num_victims].oom_score_adj = tsk.oom_score_adj;
+               selected[num_victims].size = tsk.size;
+               total_victim_size += tsk.size >> 10;
+               num_victims++;
        }
 
        g_array_free(victim_candidates, true);
 
        fclose(f);
-       *total_size = total_victim_size;
-       return sel;
+       return num_victims;
+
+}
+
+static inline int is_dynamic_process_killer(int flags) {
+       return ((flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK));
+}
+
+static int lowmem_swap_cgroup_oom_killer(int flags)
+{
+       int ret;
+       char appname[PATH_MAX];
+       int count = 0;
+       char buf[LOWMEM_PATH_MAX] = {0, };
+       FILE *f;
+       unsigned int tsize = 0;
+       int swap_type;
+
+       swap_type = swap_status(SWAP_GET_TYPE, NULL);
+       if (swap_type <= SWAP_OFF)
+               return count;
+
+       sprintf(buf, "%s/memory/swap/cgroup.procs",
+                       MEMCG_PATH);
+
+       f = fopen(buf, "r");
+       if (!f) {
+               _E("%s open failed, %d", buf, f);
+               return RESOURCED_ERROR_FAIL;
+       }
+
+       while (fgets(buf, 32, f) != NULL) {
+               pid_t tpid = 0;
+               int toom = 0;
+
+               tpid = atoi(buf);
+
+               if (proc_get_oom_score_adj(tpid, &toom) < 0) {
+                       _D("pid(%d) was already terminated", tpid);
+                       continue;
+               }
+
+               if (!get_mem_usage_by_pid(tpid, &tsize)) {
+                       _D("pid(%d) size is not available\n", tpid);
+                       continue;
+               }
+
+               /* To Do: skip by checking pgid? */
+               if (toom < OOMADJ_BACKGRD_UNLOCKED)
+                       continue;
+
+               ret = proc_get_cmdline(tpid, appname);
+               if (ret == RESOURCED_ERROR_FAIL)
+                       continue;
+
+               /* make memps log for killing application firstly */
+               if (count == 0)
+                       make_memps_log(MEMPS_LOG_FILE, tpid, appname);
+
+               count++;
+
+               proc_remove_process_list(tpid);
+               kill(tpid, SIGKILL);
+               _E("we killed, lowmem lv2 = %d (%s) score = %d, size = %u KB\n",
+                               tpid, appname, toom, tsize);
+               if (is_dynamic_process_killer(flags) &&
+                   count >= MAX_SWAP_VICTIMS)
+                       break;
+       }
+
+       fclose(f);
 
+       _I("number of swap victims = %d\n", count);
+       if (!(flags & OOM_FORCE) && (count >= MAX_SWAP_VICTIMS))
+               usleep(OOM_MULTIKILL_WAIT);
+
+       return count;
 }
 
-/* Find victims: BACKGROUND */
-static int lowmem_get_memory_cgroup_victims(struct task_info *selected, int force)
+/* Find victims: (SWAP -> ) BACKGROUND */
+static int lowmem_get_memory_cgroup_victims(struct task_info *selected,
+       int flags)
 {
-       int i, count = 0;
-       unsigned available, should_be_freed = 0, total_size = 0;
-       struct mem_info mi;
+       int i, swap_victims, count = 0;
+       unsigned int available, should_be_freed = 0;
 
-       if (force ) {
-               count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND, count,
-                               MAX_FD_VICTIMS, selected,
-                               &total_size, 0, force);
+       swap_victims = lowmem_swap_cgroup_oom_killer(flags);
+
+       if ((flags & OOM_FORCE) && swap_victims < MAX_FD_VICTIMS) {
+               count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
+                               MAX_FD_VICTIMS - swap_victims, selected,
+                               0, flags);
+               _D("kill %d victims in %s cgroup",
+                       count, memcg_class[MEMCG_BACKGROUND].cgroup_name);
                return count;
        }
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       available = get_available();
        if (available < memcg_class[MEMCG_MEMORY].thres_leave)
                should_be_freed = memcg_class[MEMCG_MEMORY].thres_leave - available;
 
        _I("should_be_freed = %u MB", should_be_freed);
+       if (should_be_freed == 0 || swap_victims >= num_max_victims)
+               return count;
 
-       if (should_be_freed) {
-               for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
-                       count = lowmem_get_cgroup_victims(i, count,
-                                               MAX_MEMORY_CGROUP_VICTIMS, selected,
-                                               &total_size, should_be_freed,
-                                               force);
-                       if (count >= MAX_MEMORY_CGROUP_VICTIMS || total_size >= should_be_freed)
-                               break;
+       for (i = MEMCG_MAX_GROUPS - 1; i >= 0; i--) {
+               if ((flags & OOM_TIMER_CHECK) && i < MEMCG_BACKGROUND &&
+                       available > thresholds[MEMNOTIFY_MEDIUM]) {
+                       _D("in timer, not kill fg app, available %u > threshold %u",
+                               available, thresholds[MEMNOTIFY_MEDIUM]);
+                       return count;
                }
+
+               count = lowmem_get_cgroup_victims(i,
+                               num_max_victims - swap_victims,
+                               selected, should_be_freed, flags);
+               if (count > 0) {
+                       _D("kill %d victims in %s cgroup",
+                               count, memcg_class[i].cgroup_name);
+                       return count;
+               } else
+                       _D("There are no victims to be killed in %s cgroup",
+                                       memcg_class[i].cgroup_name);
+
        }
 
        return count;
 }
 
-static int lowmem_get_victims(int idx, struct task_info *selected, int force)
+static int lowmem_get_victims(int idx, struct task_info *selected,
+       int flags)
 {
        int count = 0;
-       unsigned total_size = 0;
 
        if (idx == MEMCG_MEMORY)
-               count = lowmem_get_memory_cgroup_victims(selected, force);
+               count = lowmem_get_memory_cgroup_victims(selected, flags);
        else
-               count = lowmem_get_cgroup_victims(idx, count,
+               count = lowmem_get_cgroup_victims(idx,
                                        MAX_CGROUP_VICTIMS, selected,
-                                       &total_size,
-                                       memcg_class[idx].thres_leave, force);
+                                       memcg_class[idx].thres_leave,
+                                       flags);
 
        return count;
 }
 
-/* To Do: decide the number of victims based on size */
-void lowmem_oom_killer_cb(int memcg_idx, int force)
+static Eina_Bool send_sigkill_cb(void *data)
 {
-       const pid_t self = getpid();
-       int pid, ret, oom_score_adj, i;
-       char appname[PATH_MAX];
-       unsigned total_size = 0, size;
-       struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
-       int count = 0;
+       int i = 0;
 
-       /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
-       count = lowmem_get_victims(memcg_idx, selected, force);
+       _D("kill by SIGKILL timer tasks num = %d", killed_tasks.num);
 
-       if (count == 0) {
-               _D("get %s cgroup victim is failed",
-               memcg_class[memcg_idx].cgroup_name);
-               return;
+       for (i = 0; i < killed_tasks.num; i++) {
+               kill(killed_tasks.pids[i], SIGKILL);
+               _D("killed %d by SIGKILL", killed_tasks.pids[i]);
        }
 
+       killed_tasks.num = 0;
+       ecore_timer_del(oom_sigkill_timer);
+       oom_sigkill_timer = NULL;
+       return ECORE_CALLBACK_CANCEL;
+
+}
+
+static int lowmem_kill_victims(int memcg_idx,
+       int count, struct task_info *selected, int flags)
+{
+       const pid_t self = getpid();
+       int pid, ret, oom_score_adj, i;
+       unsigned total_size = 0, size;
+       char appname[PATH_MAX];
+
        for (i = 0; i < count; i++) {
                /* check current memory status */
-               if (memcg_idx != MEMCG_MEMORY && lowmem_check_current_state(memcg_idx) >= 0)
-                       return;
+               if (!(flags & OOM_FORCE) && memcg_idx != MEMCG_MEMORY &&
+                   lowmem_check_current_state(memcg_idx) >= 0)
+                       return count;
 
                pid = selected[i].pid;
                oom_score_adj = selected[i].oom_score_adj;
@@ -714,13 +877,16 @@ void lowmem_oom_killer_cb(int memcg_idx, int force)
 
                total_size += size;
 
-               if (force)
+               proc_remove_process_list(pid);
+               if (flags & OOM_FORCE) {
                        kill(pid, SIGTERM);
-               else
+                       if (killed_tasks.num < MAX_MEMORY_CGROUP_VICTIMS)
+                               killed_tasks.pids[killed_tasks.num++] = pid;
+               } else
                        kill(pid, SIGKILL);
 
-               _E("we killed, lowmem lv2 = %d (%s) oom = %d, size = %u KB, victim total size = %u KB\n",
-                               pid, appname, oom_score_adj, size, total_size);
+               _E("we killed, force(%d), lowmem lv2 = %d (%s) score = %d, size = %u KB, victim total size = %u KB\n",
+                               flags & OOM_FORCE, pid, appname, oom_score_adj, size, total_size);
 
                if (memcg_idx >= MEMCG_FOREGROUND &&
                        memcg_idx < MEMCG_BACKGROUND)
@@ -732,12 +898,85 @@ void lowmem_oom_killer_cb(int memcg_idx, int force)
                if (i != 0)
                        make_memps_log(MEMPS_LOG_FILE, pid, appname);
        }
+
+       return count;
+}
+
+int lowmem_oom_killer_cb(int memcg_idx, int flags)
+{
+       struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
+       int count = 0;
+
+       /* get multiple victims from /sys/fs/cgroup/memory/.../tasks */
+       count = lowmem_get_victims(memcg_idx, selected, flags);
+
+       if (count == 0) {
+               _D("get %s cgroup victim is failed",
+               memcg_class[memcg_idx].cgroup_name);
+               return count;
+       }
+
+       count = lowmem_kill_victims(memcg_idx, count, selected, flags);
+       clear_logs(MEMPS_LOG_PATH);
+       logging_control(LOGGING_UPDATE_STATE, NULL);
+
+       return count;
+}
+
+void lowmem_dynamic_process_killer(int type)
+{
+       struct task_info selected[MAX_MEMORY_CGROUP_VICTIMS] = {{0, 0, OOMADJ_SU, 0}, };
+       int count = 0;
+       unsigned available = get_available();
+       unsigned should_be_freed;
+       int flags = OOM_FORCE;
+       int swap_victims;
+
+       if (!dynamic_process_threshold[type])
+               return;
+
+       if (available >= dynamic_process_threshold[type])
+               return;
+
+       change_memory_state(MEMNOTIFY_LOW, 1);
+       swap_victims = lowmem_swap_cgroup_oom_killer(flags);
+       if (swap_victims >= MAX_SWAP_VICTIMS)
+               goto start_timer;
+
+       available = get_available();
+       if (available >= dynamic_process_leave[type])
+               return;
+
+       should_be_freed = dynamic_process_leave[type] - available;
+       _D("run dynamic killer, type=%d, available=%d, should_be_freed = %u", type, available, should_be_freed);
+       count = lowmem_get_cgroup_victims(MEMCG_BACKGROUND,
+                       num_max_victims - swap_victims, selected,
+                       should_be_freed, flags);
+
+       if (count == 0) {
+               _D("get victim for dynamic process is failed");
+               return;
+       }
+
+       lowmem_kill_victims(MEMCG_BACKGROUND, count, selected, flags);
+       change_memory_state(MEMNOTIFY_NORMAL, 0);
+
+start_timer:
+       if (oom_sigkill_timer == NULL) {
+               _D("start timer to sigkill tasks");
+               oom_sigkill_timer =
+                       ecore_timer_add(OOM_SIGKILL_WAIT, send_sigkill_cb,
+                                       NULL);
+       } else
+               killed_tasks.num = 0;
 }
 
 static void *lowmem_oom_killer_pthread(void *arg)
 {
        int ret = 0;
 
+       setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
+
        while (1) {
                /*
                 * When signalled by main thread,
@@ -756,8 +995,9 @@ static void *lowmem_oom_killer_pthread(void *arg)
                        break;
                }
 
-               _I("oom thread conditional signal received");
-               lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+               _I("oom thread conditional signal received and start");
+               lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_NONE);
+               _I("lowmem_oom_killer_cb finished");
 
                ret = pthread_mutex_unlock(&oom_mutex);
                if ( ret ) {
@@ -779,6 +1019,9 @@ static char *convert_to_str(int mem_state)
        case MEMNOTIFY_NORMAL:
                tmp = "mem normal";
                break;
+       case MEMNOTIFY_SWAP:
+               tmp = "mem swap";
+               break;
        case MEMNOTIFY_LOW:
                tmp = "mem low";
                break;
@@ -801,6 +1044,32 @@ static void change_lowmem_state(unsigned int mem_state)
        cur_mem_state = mem_state;
 }
 
+static void lowmem_swap_memory(void)
+{
+       pid_t pid;
+       int swap_type;
+
+       if (cur_mem_state == MEMNOTIFY_NORMAL)
+               return;
+
+       swap_type = swap_status(SWAP_GET_TYPE, NULL);
+
+       if (swap_type == SWAP_ON) {
+               while (1)
+               {
+                       pid = (pid_t)swap_status(SWAP_GET_CANDIDATE_PID, NULL);
+                       if (!pid)
+                               break;
+                       _I("swap cgroup entered : pid : %d", (int)pid);
+                       resourced_notify(RESOURCED_NOTIFIER_SWAP_MOVE_CGROUP, (void*)&pid);
+               }
+               if (swap_status(SWAP_GET_STATUS, NULL) == SWAP_OFF)
+                       resourced_notify(RESOURCED_NOTIFIER_SWAP_RESTART, NULL);
+               resourced_notify(RESOURCED_NOTIFIER_SWAP_START, NULL);
+       }
+}
+
+
 static void normal_act(void)
 {
        int ret, status;
@@ -815,6 +1084,20 @@ static void normal_act(void)
        change_lowmem_state(MEMNOTIFY_NORMAL);
 }
 
+static void swap_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);
+       change_lowmem_state(MEMNOTIFY_SWAP);
+}
+
 static void low_act(void)
 {
        int ret, status;
@@ -825,7 +1108,6 @@ static void low_act(void)
                _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
 
        change_lowmem_state(MEMNOTIFY_LOW);
-       remove_shm();
 
        /* Since vconf for soft warning could be set during low memory check,
         * we set it only when the current status is not soft warning.
@@ -837,11 +1119,10 @@ static void low_act(void)
 
 static Eina_Bool medium_cb(void *data)
 {
-       struct mem_info mi;
-       unsigned available;
+       unsigned int available;
+       int count = 0;
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       available = get_available();
        _D("available = %u, timer run until reaching leave threshold", available);
 
        if (available >= memcg_class[MEMCG_MEMORY].thres_leave && oom_check_timer != NULL) {
@@ -853,8 +1134,21 @@ static Eina_Bool medium_cb(void *data)
        }
 
        _I("cannot reach leave threshold, timer again");
-       lowmem_oom_killer_cb(MEMCG_MEMORY, 0);
+       count = lowmem_oom_killer_cb(MEMCG_MEMORY, OOM_TIMER_CHECK);
 
+       /*
+        * After running oom killer in timer, but there is no victim,
+        * stop timer.
+        */
+       if (!count && available >= thresholds[MEMNOTIFY_MEDIUM] &&
+           oom_check_timer != NULL) {
+               ecore_timer_del(oom_check_timer);
+               oom_check_timer = NULL;
+               _D("oom_check_timer deleted, available %u > threshold %u",
+                       available, thresholds[MEMNOTIFY_MEDIUM]);
+               normal_act();
+               return ECORE_CALLBACK_CANCEL;
+       }
        return ECORE_CALLBACK_RENEW;
 }
 
@@ -865,25 +1159,15 @@ static void medium_act(void)
        change_lowmem_state(MEMNOTIFY_MEDIUM);
 
        /* signal to lowmem_oom_killer_pthread to start killer */
-       ret = pthread_mutex_lock(&oom_mutex);
-       if ( ret ) {
-               _E("medium_act::pthread_mutex_lock() failed, %d", ret);
-               return;
-       }
-
-       ret = pthread_cond_signal(&oom_cond);
-       if ( ret ) {
-               _E("medium_act::pthread_cond_wait() failed, %d", ret);
-               pthread_mutex_unlock(&oom_mutex);
-               return;
-       }
-
-       _I("send signal lowmem oom killer");
-       ret = pthread_mutex_unlock(&oom_mutex);
-       if ( ret ) {
-               _E("medium_act::pthread_mutex_unlock() failed, %d", ret);
+       ret = pthread_mutex_trylock(&oom_mutex);
+       if (ret) {
+               _E("medium_act::pthread_mutex_trylock() failed, %d, errno: %d", ret, errno);
                return;
        }
+       _I("oom mutex trylock success");
+       pthread_cond_signal(&oom_cond);
+       _I("send signal to oom killer thread");
+       pthread_mutex_unlock(&oom_mutex);
 
        vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
                        VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
@@ -984,7 +1268,7 @@ static void memory_cgroup_medium_act(int memcg_idx)
        if ((memcg_idx >= MEMCG_FOREGROUND && memcg_idx < MEMCG_BACKGROUND)
            && is_fg_victim_killed(memcg_idx)) {
                show_foreground_procs(memcg_idx);
-               lowmem_oom_killer_cb(memcg_idx, 0);
+               lowmem_oom_killer_cb(memcg_idx, OOM_NONE);
        }
 }
 
@@ -996,7 +1280,7 @@ static unsigned int lowmem_eventfd_read(int fd)
        return ret;
 }
 
-static unsigned int check_mem_state(unsigned available)
+static unsigned int check_mem_state(unsigned int available)
 {
        int mem_state;
        for (mem_state = MEMNOTIFY_MAX_LEVELS -1; mem_state > MEMNOTIFY_NORMAL; mem_state--) {
@@ -1007,19 +1291,51 @@ static unsigned int check_mem_state(unsigned available)
        return mem_state;
 }
 
+void change_memory_state(int state, int force)
+{
+       unsigned int available;
+       int mem_state;
+
+       if (force) {
+               mem_state = state;
+       } else {
+               available = get_available();
+               mem_state = check_mem_state(available);
+               _D("available = %u, mem_state = %d", available, mem_state);
+       }
+
+       switch (mem_state) {
+       case MEMNOTIFY_NORMAL:
+               normal_act();
+               break;
+       case MEMNOTIFY_SWAP:
+               swap_act();
+               break;
+       case MEMNOTIFY_LOW:
+               low_act();
+               break;
+       case MEMNOTIFY_MEDIUM:
+               medium_act();
+               break;
+       default:
+               assert(0);
+       }
+}
+
 static void lowmem_handler(void)
 {
-       struct mem_info mi;
-       unsigned available;
+       static unsigned int prev_available;
+       unsigned int available;
        int mem_state;
 
-       get_mem_info(&mi);
-       available = mi.real_free + mi.reclaimable;
+       available = get_available();
 
-       mem_state = check_mem_state(available);
-       _D("available = %u, mem_state = %d", available, mem_state);
+       if (prev_available == available)
+               return;
 
+       mem_state = check_mem_state(available);
        lowmem_process(mem_state);
+       prev_available = available;
 }
 
 static void lowmem_cgroup_handler(int memcg_idx)
@@ -1207,53 +1523,80 @@ static int load_mem_config(struct parse_result *result, void *user_data)
        return RESOURCED_ERROR_NONE;
 }
 
-static int set_thresholds(const char * section_name, const struct parse_result *result)
+static int set_memory_config(const char * section_name, const struct parse_result *result)
 {
-       if (!result || !section_name)
-               return -EINVAL;
+       if (!result || !section_name)
+               return -EINVAL;
 
-       if (strcmp(result->section, section_name))
-               return RESOURCED_ERROR_NONE;
+       if (strcmp(result->section, section_name))
+               return RESOURCED_ERROR_NONE;
 
-       if (!strcmp(result->name, "ThresholdLow")) {
-              int value = atoi(result->value);
-              set_threshold(MEMNOTIFY_LOW, value);
-       } else if (!strcmp(result->name, "ThresholdMedium")) {
-              int value = atoi(result->value);
-              set_threshold(MEMNOTIFY_MEDIUM, value);
-       } else if (!strcmp(result->name, "ThresholdLeave")) {
-              int value = atoi(result->value);
-              set_leave_threshold(value);
-       } else if (!strcmp(result->name, "ForegroundRatio")) {
-              float value = atof(result->value);
-              set_foreground_ratio(value);
-       }
-       return RESOURCED_ERROR_NONE;
+       if (!strcmp(result->name, "ThresholdSwap")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_SWAP, value);
+       } else if (!strcmp(result->name, "ThresholdLow")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_LOW, value);
+       } else if (!strcmp(result->name, "ThresholdMedium")) {
+               int value = atoi(result->value);
+               set_threshold(MEMNOTIFY_MEDIUM, value);
+       } else if (!strcmp(result->name, "ThresholdLeave")) {
+               int value = atoi(result->value);
+               set_leave_threshold(value);
+       } else if (!strcmp(result->name, "ForegroundRatio")) {
+               float value = atof(result->value);
+               set_foreground_ratio(value);
+       } else if (!strcmp(result->name, "NumMaxVictims")) {
+               int value = atoi(result->value);
+               num_max_victims = value;
+               _D("set number of max victims as %d", num_max_victims);
+       } else if (!strcmp(result->name, "DynamicThreshold")) {
+               int value = atoi(result->value);
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = value;
+               _D("set dynamic process threshold as %d",
+                       dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
+       } else if (!strcmp(result->name, "DynamicLeave")) {
+               int value = atoi(result->value);
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = value;
+               _D("set dynamic process leave threshold as %d",
+                       dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
+       } else if (!strcmp(result->name, "DynamicThresholdLaunch")) {
+               int value = atoi(result->value);
+               dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = value;
+               _D("set dynamic process threshold as %d",
+                       dynamic_process_threshold[DYNAMIC_KILL_LUNCH]);
+       } else if (!strcmp(result->name, "DynamicLeaveLaunch")) {
+               int value = atoi(result->value);
+               dynamic_process_leave[DYNAMIC_KILL_LUNCH] = value;
+               _D("set dynamic process leave threshold as %d",
+                       dynamic_process_leave[DYNAMIC_KILL_LUNCH]);
+       }
+       return RESOURCED_ERROR_NONE;
 }
 
 static int memory_load_64_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory64", result);
+       return set_memory_config("Memory64", result);
 }
 
 static int memory_load_256_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory256", result);
+       return set_memory_config("Memory256", result);
 }
 
 static int memory_load_512_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory512", result);
+       return set_memory_config("Memory512", result);
 }
 
 static int memory_load_1024_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory1024", result);
+       return set_memory_config("Memory1024", result);
 }
 
 static int memory_load_2048_config(struct parse_result *result, void *user_data)
 {
-       return set_thresholds("Memory2048", result);
+       return set_memory_config("Memory2048", result);
 }
 
 /* init thresholds depending on total ram size. */
@@ -1265,40 +1608,58 @@ static void init_thresholds(void)
 
        if (total_ramsize <= MEM_SIZE_64) {
                /* set thresholds for ram size 64M */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_THRES;
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_64_LEAVE;
+               set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_64_THRES_SWAP);
                set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_64_THRES_LOW);
                set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_64_THRES_MEDIUM);
                set_leave_threshold(MEMCG_MEMORY_64_THRES_LEAVE);
                config_parse(MEM_CONF_FILE, memory_load_64_config, NULL);
        } else if (total_ramsize <= MEM_SIZE_256) {
                /* set thresholds for ram size 256M */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_THRES;
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_256_LEAVE;
+               set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_256_THRES_SWAP);
                set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_256_THRES_LOW);
                set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_256_THRES_MEDIUM);
                set_leave_threshold(MEMCG_MEMORY_256_THRES_LEAVE);
                config_parse(MEM_CONF_FILE, memory_load_256_config, NULL);
        } else if (total_ramsize <= MEM_SIZE_512) {
                /* set thresholds for ram size 512M */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_THRES;
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_512_LEAVE;
+               dynamic_process_threshold[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_THRESLAUNCH;
+               dynamic_process_leave[DYNAMIC_KILL_LUNCH] = DYNAMIC_PROCESS_512_LEAVELAUNCH;
+               set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_512_THRES_SWAP);
                set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_512_THRES_LOW);
                set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_512_THRES_MEDIUM);
                set_leave_threshold(MEMCG_MEMORY_512_THRES_LEAVE);
                config_parse(MEM_CONF_FILE, memory_load_512_config, NULL);
        } else if (total_ramsize <= MEM_SIZE_1024) {
                /* set thresholds for ram size more than 1G */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_THRES;
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_1024_LEAVE;
+               set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_1024_THRES_SWAP);
                set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_1024_THRES_LOW);
                set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_1024_THRES_MEDIUM);
                set_leave_threshold(MEMCG_MEMORY_1024_THRES_LEAVE);
                config_parse(MEM_CONF_FILE, memory_load_1024_config, NULL);
        } else {
-               /* set thresholds for ram size more than 2G */
+               dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_THRES;
+               dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP] = DYNAMIC_PROCESS_2048_LEAVE;
+               set_threshold(MEMNOTIFY_SWAP, MEMCG_MEMORY_2048_THRES_SWAP);
                set_threshold(MEMNOTIFY_LOW, MEMCG_MEMORY_2048_THRES_LOW);
                set_threshold(MEMNOTIFY_MEDIUM, MEMCG_MEMORY_2048_THRES_MEDIUM);
                set_leave_threshold(MEMCG_MEMORY_2048_THRES_LEAVE);
                config_parse(MEM_CONF_FILE, memory_load_2048_config, NULL);
        }
 
-       for (i = MEMNOTIFY_NORMAL; i < MEMNOTIFY_MAX_LEVELS; i++)
+       for (i = MEMNOTIFY_SWAP; i < MEMNOTIFY_MAX_LEVELS; i++)
                _I("set threshold for %d to %u", i, thresholds[i]);
 
        _I("set thres_leave to %u", memcg_class[MEMCG_MEMORY].thres_leave);
+       _I("set dynamic process threshold to %u", dynamic_process_threshold[DYNAMIC_KILL_LARGEHEAP]);
+       _I("set dynamic process leave to %u", dynamic_process_leave[DYNAMIC_KILL_LARGEHEAP]);
 }
 
 static int create_foreground_memcg(void)
@@ -1369,11 +1730,37 @@ static int init_memcg(void)
        return ret;
 }
 
+static void lowmem_check(void)
+{
+       unsigned int available;
+
+       available = get_available();
+       _D("available = %u", available);
 
-static int find_foreground_cgroup(void) {
+       if(cur_mem_state != MEMNOTIFY_SWAP &&
+               (available <= thresholds[MEMNOTIFY_SWAP] &&
+                       available > thresholds[MEMNOTIFY_LOW])) {
+               swap_act();
+
+       }
+}
+
+static int find_foreground_cgroup(struct proc_process_info_t *process_info) {
        int fg, min_fg = -1;
        unsigned int min_usage = UINT_MAX;
 
+       /*
+        * if this process group is already in one of the foreground cgroup,
+        * put all of the process in this group into the same cgroup.
+        */
+       if (process_info && process_info->memcg_idx >= MEMCG_FOREGROUND &&
+           process_info->memcg_idx < MEMCG_FOREGROUND + NUM_FOREGROUND)
+               return process_info->memcg_idx;
+
+       /*
+        * if any of the process in this group is not in foreground,
+        * find foreground cgroup with minimum usage
+        */
        for (fg = MEMCG_FOREGROUND; fg < MEMCG_BACKGROUND; fg++) {
                unsigned int usage;
                usage = get_mem_usage(fg);
@@ -1395,28 +1782,34 @@ static int find_foreground_cgroup(void) {
        return min_fg;
 }
 
-void lowmem_move_memcgroup(int pid, int oom_score_adj)
+static void lowmem_move_memcgroup(int pid, int oom_score_adj)
 {
        char buf[LOWMEM_PATH_MAX] = {0,};
        FILE *f;
-       int size;
+       int size, background = 0;
+       unsigned long swap_args[1] = {0,};
+       struct proc_process_info_t *process_info =
+               find_process_info(NULL, pid, NULL);
 
        if (oom_score_adj >= OOMADJ_BACKGRD_LOCKED) {
                sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
+               proc_set_process_info_memcg(process_info, MEMCG_BACKGROUND);
+               background = 1;
        } else if (oom_score_adj >= OOMADJ_FOREGRD_LOCKED &&
                                        oom_score_adj < OOMADJ_BACKGRD_LOCKED) {
-               int ret;
-               ret = find_foreground_cgroup();
+               int ret = find_foreground_cgroup(process_info);
                if (ret == RESOURCED_ERROR_FAIL) {
                        _E("cannot find foreground cgroup");
                        return;
                }
                sprintf(buf, "%s/memory/foreground%d/cgroup.procs", MEMCG_PATH, ret);
+               proc_set_process_info_memcg(process_info, ret);
        } else
                return;
 
-
-               _D("buf : %s, pid : %d, oom : %d", buf, pid, oom_score_adj);
+       swap_args[0] = (unsigned long)pid;
+       if (!swap_status(SWAP_CHECK_PID, swap_args) || !background) {
+               _D("buf : %s, pid : %d, score : %d", buf, pid, oom_score_adj);
                f = fopen(buf, "w");
                if (!f) {
                        _E("%s open failed", buf);
@@ -1426,29 +1819,28 @@ void lowmem_move_memcgroup(int pid, int oom_score_adj)
                if (fwrite(buf, size, 1, f) != 1)
                        _E("fwrite cgroup tasks : %d\n", pid);
                fclose(f);
-
+       }
+       if (background) {
+               lowmem_check();
+               lowmem_swap_memory();
+       }
 }
 
-void lowmem_cgroup_foregrd_manage(int currentpid)
+static void lowmem_cgroup_foregrd_manage(int currentpid)
 {
-       char buf[LOWMEM_PATH_MAX] = {0,};
-       int pid, pgid;
-       FILE *f;
-       sprintf(buf, "%s/memory/background/cgroup.procs", MEMCG_PATH);
-       f = fopen(buf, "r");
-       if (!f) {
-               _E("%s open failed", buf);
+       GSList *iter;
+       struct proc_process_info_t *process_info =
+               find_process_info(NULL, currentpid, NULL);
+
+       if (!process_info)
                return;
+
+       gslist_for_each_item(iter, process_info->pids) {
+               struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
+
+               if (pid_info->type == RESOURCED_APP_TYPE_GROUP)
+                       lowmem_move_memcgroup(pid_info->pid, OOMADJ_FOREGRD_UNLOCKED);
        }
-       while (fgets(buf, LOWMEM_PATH_MAX, f) != NULL) {
-               pid = atoi(buf);
-               if (currentpid == pid)
-                       continue;
-               pgid = getpgid(pid);
-               if (currentpid == pgid)
-                       lowmem_move_memcgroup(pid, OOMADJ_APP_LIMIT);
-       }
-       fclose(f);
 }
 
 static int oom_thread_create(void)
@@ -1471,6 +1863,20 @@ static int oom_thread_create(void)
        return ret;
 }
 
+static int lowmem_app_launch_cb(void *data)
+{
+       struct proc_status *p_data = (struct proc_status*)data;
+       struct proc_process_info_t *process_info;
+       int ret = 0;
+       ret_value_msg_if(p_data == NULL, RESOURCED_ERROR_FAIL,
+               "Please provide valid argument!");
+       process_info = (struct proc_process_info_t *)p_data->processinfo;
+
+       if (process_info && !(process_info->type & PROC_LARGE_HEAP))
+               lowmem_dynamic_process_killer(DYNAMIC_KILL_LUNCH);
+       return ret;
+}
+
 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
 int lowmem_init(void)
 {
@@ -1507,6 +1913,7 @@ int lowmem_init(void)
        }
 
        lowmem_dbus_init();
+       register_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
 
        return ret;
 }
@@ -1533,15 +1940,31 @@ static int resourced_memory_control(void *data)
 
 static int resourced_memory_init(void *data)
 {
+       lowmem_ops = &memory_modules_ops;
+
        return lowmem_init();
 }
 
 static int resourced_memory_finalize(void *data)
 {
+       unregister_notifier(RESOURCED_NOTIFIER_APP_LAUNCH, lowmem_app_launch_cb);
+       return RESOURCED_ERROR_NONE;
+}
+
+int lowmem_control(enum lowmem_control_type type, unsigned long *args)
+{
+       struct lowmem_data_type l_data;
+
+       if (lowmem_ops) {
+               l_data.control_type = type;
+               l_data.args = args;
+               return lowmem_ops->control(&l_data);
+       }
+
        return RESOURCED_ERROR_NONE;
 }
 
-static struct module_ops memory_modules_ops = {
+static const struct module_ops memory_modules_ops = {
        .priority       = MODULE_PRIORITY_NORMAL,
        .name           = "lowmem",
        .init           = resourced_memory_init,