4 * Copyright (c) 2012 - 2019 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @file vmpressure-lowmem-handler.c
22 * @desc lowmem handler using memcgroup
24 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
38 #include <sys/types.h>
41 #include <sys/sysinfo.h>
43 #include <sys/resource.h>
46 #include <eventsystem.h>
51 #include "lowmem-handler.h"
52 #include "proc-common.h"
55 #include "resourced.h"
58 #include "config-parser.h"
60 #include "swap-common.h"
62 #include "memory-cgroup.h"
63 #include "heart-common.h"
64 #include "proc-main.h"
65 #include "dbus-handler.h"
67 #include "fd-handler.h"
68 #include "resourced-helper-worker.h"
69 #include "safe-kill.h"
70 #include "dedup-common.h"
72 #define LOWMEM_THRES_INIT 0
74 #define MEMPS_EXEC_PATH "usr/bin/memps"
75 #define MEM_CONF_FILE RD_CONFIG_FILE(limiter)
76 #define MEM_SECTION "Memory"
77 #define MEM_VIP_SECTION "VIP_PROCESS"
78 #define MEM_VIP_PREDEFINE "PREDEFINE"
79 #define MEM_POPUP_SECTION "POPUP"
80 #define MEM_POPUP_STRING "oom_popup"
81 #define MEM_BG_RECLAIM_SECTION "BackgroundReclaim"
82 #define MEM_BG_RECLAIM_STRING "AfterScreenDim"
83 #define MEM_LOGGING_SECTION "Logging"
86 #define MAX_VICTIMS_BETWEEN_CHECK 3
87 #define MAX_PROACTIVE_LOW_VICTIMS 2
88 #define MAX_PROACTIVE_HIGH_VICTIMS 4
89 #define FOREGROUND_VICTIMS 1
90 #define OOM_TIMER_INTERVAL 2
91 #define OOM_KILLER_PRIORITY -20
92 #define THRESHOLD_MARGIN 10 /* MB */
94 #define MEM_SIZE_64 64 /* MB */
95 #define MEM_SIZE_256 256 /* MB */
96 #define MEM_SIZE_448 448 /* MB */
97 #define MEM_SIZE_512 512 /* MB */
98 #define MEM_SIZE_768 768 /* MB */
99 #define MEM_SIZE_1024 1024 /* MB */
100 #define MEM_SIZE_2048 2048 /* MB */
102 /* thresholds for 64M RAM*/
103 #define PROACTIVE_64_THRES 10 /* MB */
104 #define PROACTIVE_64_LEAVE 30 /* MB */
105 #define CGROUP_ROOT_64_THRES_DEDUP 16 /* MB */
106 #define CGROUP_ROOT_64_THRES_SWAP 15 /* MB */
107 #define CGROUP_ROOT_64_THRES_LOW 8 /* MB */
108 #define CGROUP_ROOT_64_THRES_MEDIUM 5 /* MB */
109 #define CGROUP_ROOT_64_THRES_LEAVE 8 /* MB */
110 #define CGROUP_ROOT_64_NUM_VICTIMS 1
112 /* thresholds for 256M RAM */
113 #define PROACTIVE_256_THRES 50 /* MB */
114 #define PROACTIVE_256_LEAVE 80 /* MB */
115 #define CGROUP_ROOT_256_THRES_DEDUP 60 /* MB */
116 #define CGROUP_ROOT_256_THRES_SWAP 40 /* MB */
117 #define CGROUP_ROOT_256_THRES_LOW 20 /* MB */
118 #define CGROUP_ROOT_256_THRES_MEDIUM 10 /* MB */
119 #define CGROUP_ROOT_256_THRES_LEAVE 20 /* MB */
120 #define CGROUP_ROOT_256_NUM_VICTIMS 2
122 /* threshold for 448M RAM */
123 #define PROACTIVE_448_THRES 80 /* MB */
124 #define PROACTIVE_448_LEAVE 100 /* MB */
125 #define CGROUP_ROOT_448_THRES_DEDUP 120 /* MB */
126 #define CGROUP_ROOT_448_THRES_SWAP 100 /* MB */
127 #define CGROUP_ROOT_448_THRES_LOW 60 /* MB */
128 #define CGROUP_ROOT_448_THRES_MEDIUM 50 /* MB */
129 #define CGROUP_ROOT_448_THRES_LEAVE 70 /* MB */
130 #define CGROUP_ROOT_448_NUM_VICTIMS 5
132 /* threshold for 512M RAM */
133 #define PROACTIVE_512_THRES 100 /* MB */
134 #define PROACTIVE_512_LEAVE 80 /* MB */
135 #define CGROUP_ROOT_512_THRES_DEDUP 140 /* MB */
136 #define CGROUP_ROOT_512_THRES_SWAP 100 /* MB */
137 #define CGROUP_ROOT_512_THRES_LOW 70 /* MB */
138 #define CGROUP_ROOT_512_THRES_MEDIUM 60 /* MB */
139 #define CGROUP_ROOT_512_THRES_LEAVE 80 /* MB */
140 #define CGROUP_ROOT_512_NUM_VICTIMS 5
142 /* threshold for 768 RAM */
143 #define PROACTIVE_768_THRES 100 /* MB */
144 #define PROACTIVE_768_LEAVE 130 /* MB */
145 #define CGROUP_ROOT_768_THRES_DEDUP 180 /* MB */
146 #define CGROUP_ROOT_768_THRES_SWAP 150 /* MB */
147 #define CGROUP_ROOT_768_THRES_LOW 90 /* MB */
148 #define CGROUP_ROOT_768_THRES_MEDIUM 80 /* MB */
149 #define CGROUP_ROOT_768_THRES_LEAVE 100 /* MB */
150 #define CGROUP_ROOT_768_NUM_VICTIMS 5
152 /* threshold for more than 1024M RAM */
153 #define PROACTIVE_1024_THRES 230 /* MB */
154 #define PROACTIVE_1024_LEAVE 150 /* MB */
155 #define CGROUP_ROOT_1024_THRES_DEDUP 400 /* MB */
156 #define CGROUP_ROOT_1024_THRES_SWAP 300 /* MB */
157 #define CGROUP_ROOT_1024_THRES_LOW 120 /* MB */
158 #define CGROUP_ROOT_1024_THRES_MEDIUM 100 /* MB */
159 #define CGROUP_ROOT_1024_THRES_LEAVE 150 /* MB */
160 #define CGROUP_ROOT_1024_NUM_VICTIMS 5
162 /* threshold for more than 2048M RAM */
163 #define PROACTIVE_2048_THRES 200 /* MB */
164 #define PROACTIVE_2048_LEAVE 500 /* MB */
165 #define CGROUP_ROOT_2048_THRES_DEDUP 400 /* MB */
166 #define CGROUP_ROOT_2048_THRES_SWAP 300 /* MB */
167 #define CGROUP_ROOT_2048_THRES_LOW 200 /* MB */
168 #define CGROUP_ROOT_2048_THRES_MEDIUM 160 /* MB */
169 #define CGROUP_ROOT_2048_THRES_LEAVE 300 /* MB */
170 #define CGROUP_ROOT_2048_NUM_VICTIMS 10
172 /* threshold for more than 3072M RAM */
173 #define PROACTIVE_3072_THRES 300 /* MB */
174 #define PROACTIVE_3072_LEAVE 700 /* MB */
175 #define CGROUP_ROOT_3072_THRES_DEDUP 600 /* MB */
176 #define CGROUP_ROOT_3072_THRES_SWAP 500 /* MB */
177 #define CGROUP_ROOT_3072_THRES_LOW 400 /* MB */
178 #define CGROUP_ROOT_3072_THRES_MEDIUM 250 /* MB */
179 #define CGROUP_ROOT_3072_THRES_LEAVE 500 /* MB */
180 #define CGROUP_ROOT_3072_NUM_VICTIMS 10
182 static unsigned proactive_threshold_mb;
183 static unsigned proactive_leave_mb;
184 static unsigned lmk_start_threshold_mb;
186 static char *event_level = MEMCG_DEFAULT_EVENT_LEVEL;
189 * Resourced Low Memory Killer
190 * NOTE: planned to be moved to a separate file.
192 /*-------------------------------------------------*/
193 #define OOM_TIMER_INTERVAL_SEC 2
194 #define LMW_LOOP_WAIT_TIMEOUT_MSEC OOM_TIMER_INTERVAL_SEC*(G_USEC_PER_SEC)
195 #define LMW_RETRY_WAIT_TIMEOUT_MSEC (G_USEC_PER_SEC)
197 struct lowmem_control {
199 * For each queued request the following properties
200 * are required with two exceptions:
201 * - status is being set by LMK
202 * - callback is optional
204 /* Processing flags*/
206 /* Indictator for OOM score of targeted processes */
207 enum cgroup_type type;
209 /* Desired size to be restored - level to be reached (MB)*/
210 unsigned int size_mb;
211 /* Max number of processes to be considered */
213 /* Memory reclaim status */
216 * Optional - if set, will be triggered by LMK once the request
219 void (*callback) (struct lowmem_control *);
222 struct lowmem_worker {
223 pthread_t worker_thread;
229 static struct lowmem_worker lmw;
231 //static int memlog_enabled;
232 //static int memlog_nr_max = DEFAULT_MEMLOG_NR_MAX;
233 /* remove logfiles to reduce to this threshold.
234 * it is about five-sixths of the memlog_nr_max. */
235 //static int memlog_remove_batch_thres = (DEFAULT_MEMLOG_NR_MAX * 5) / 6;
236 //static char *memlog_path = DEFAULT_MEMLOG_PATH;
237 //static char *memlog_prefix[MEMLOG_MAX];
239 #define LOWMEM_WORKER_IS_ACTIVE(_lmw) g_atomic_int_get(&(_lmw)->active)
240 #define LOWMEM_WORKER_ACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 1)
241 #define LOWMEM_WORKER_DEACTIVATE(_lmw) g_atomic_int_set(&(_lmw)->active, 0)
243 #define LOWMEM_WORKER_IS_RUNNING(_lmw) g_atomic_int_get(&(_lmw)->running)
244 #define LOWMEM_WORKER_RUN(_lmw) g_atomic_int_set(&(_lmw)->running, 1)
245 #define LOWMEM_WORKER_IDLE(_lmw) g_atomic_int_set(&(_lmw)->running, 0)
247 #define LOWMEM_NEW_REQUEST() g_slice_new0(struct lowmem_control)
249 #define LOWMEM_DESTROY_REQUEST(_ctl) \
250 g_slice_free(typeof(*(_ctl)), _ctl); \
252 #define LOWMEM_SET_REQUEST(c, __flags, __type, __size, __count, __cb) \
254 (c)->flags = __flags; (c)->type = __type; \
255 (c)->size_mb= __size; (c)->count = __count; \
256 (c)->callback = __cb; \
260 #define APP_ATTR_PATH "/proc/%d/attr/current"
262 static int get_privilege(pid_t pid, char *name, size_t len)
269 snprintf(path, sizeof(path), APP_ATTR_PATH, pid);
271 fp = fopen(path, "r");
275 attr_len = fread(attr, 1, sizeof(attr) - 1, fp);
280 attr[attr_len] = '\0';
282 snprintf(name, len, "%s", attr);
286 static int is_app(pid_t pid)
292 ret = get_privilege(pid, attr, sizeof(attr));
294 _E("Failed to get privilege of PID(%d).", pid);
298 len = strlen(attr) + 1;
300 if (!strncmp("System", attr, len))
303 if (!strncmp("User", attr, len))
306 if (!strncmp("System::Privileged", attr, len))
313 static void lowmem_queue_request(struct lowmem_worker *lmw,
314 struct lowmem_control *ctl)
316 if (LOWMEM_WORKER_IS_ACTIVE(lmw))
317 g_async_queue_push(lmw->queue, ctl);
321 static void lowmem_drain_queue(struct lowmem_worker *lmw)
323 struct lowmem_control *ctl;
325 g_async_queue_lock(lmw->queue);
326 while ((ctl = g_async_queue_try_pop_unlocked(lmw->queue))) {
329 LOWMEM_DESTROY_REQUEST(ctl);
331 g_async_queue_unlock(lmw->queue);
334 static void lowmem_request_destroy(gpointer data)
336 struct lowmem_control *ctl = (struct lowmem_control*) data;
340 LOWMEM_DESTROY_REQUEST(ctl);
343 /*-------------------------------------------------*/
345 /* low memory action function for cgroup */
346 /* low memory action function */
347 static void high_mem_act(void);
348 static void swap_activate_act(void);
349 static void swap_compact_act(void);
350 static void lmk_act(void);
353 static size_t cur_mem_state = MEM_LEVEL_HIGH;
354 static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
355 static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
357 static unsigned long long totalram_bytes;
358 static unsigned long totalram_kb;
360 static struct module_ops memory_modules_ops;
361 static const struct module_ops *lowmem_ops;
362 static bool oom_popup_enable;
363 static bool oom_popup;
364 static bool memcg_swap_status;
365 static int fragmentation_size;
367 static const char *convert_cgroup_type_to_str(int type)
369 static const char *type_table[] =
370 {"/", "VIP", "High", "Medium", "Lowest"};
371 if (type >= CGROUP_ROOT && type <= CGROUP_LOW)
372 return type_table[type];
377 static const char *convert_status_to_str(int status)
379 static const char *status_table[] =
380 {"none", "done", "drop", "cont", "retry", "next_type"};
381 if(status >= LOWMEM_RECLAIM_NONE && status <= LOWMEM_RECLAIM_NEXT_TYPE)
382 return status_table[status];
383 return "error status";
386 static const char *convert_memstate_to_str(int mem_state)
388 static const char *state_table[] = {"mem high", "mem medium",
389 "mem low", "mem critical", "mem oom",};
390 if (mem_state >= 0 && mem_state < MEM_LEVEL_MAX)
391 return state_table[mem_state];
395 static int lowmem_launch_oompopup(void)
397 GVariantBuilder *const gv_builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
398 g_variant_builder_add(gv_builder, "{ss}", "_SYSPOPUP_CONTENT_", "lowmemory_oom");
400 GVariant *const params = g_variant_new("(a{ss})", gv_builder);
401 g_variant_builder_unref(gv_builder);
403 int ret = d_bus_call_method_sync_gvariant(SYSTEM_POPUP_BUS_NAME,
404 SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
405 "PopupLaunch", params);
407 g_variant_unref(params);
412 static inline void get_total_memory(void)
419 totalram_bytes = (unsigned long long)si.totalram * si.mem_unit;
420 totalram_kb = BYTE_TO_KBYTE(totalram_bytes);
422 register_totalram_bytes(totalram_bytes);
425 _E("Failed to get total ramsize from the kernel");
429 unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
431 unsigned int size_kb = 0, total_size_kb = 0;
436 * If pids are allocated only when there are multiple processes with
437 * the same pgid e.g., browser and web process. Mostly, single process
440 if (tsk->pids == NULL) {
441 ret = proc_get_ram_usage(tsk->pid, &size_kb);
443 /* If there is no proc entry for given pid the process
444 * should be abandoned during further processing
447 _D("failed to get rss memory usage of %d", tsk->pid);
452 for (index = 0; index < tsk->pids->len; index++) {
453 pid = g_array_index(tsk->pids, pid_t, index);
454 ret = proc_get_ram_usage(pid, &size_kb);
455 if (ret != RESOURCED_ERROR_NONE)
457 total_size_kb += size_kb;
460 return total_size_kb;
463 static int lowmem_kill_victim(const struct task_info *tsk,
464 int flags, int memps_log, unsigned int *victim_size)
468 char appname[PATH_MAX];
470 struct proc_app_info *pai;
474 if (pid <= 0 || pid == getpid())
475 return RESOURCED_ERROR_FAIL;
477 ret = proc_get_cmdline(pid, appname, sizeof appname);
478 if (ret == RESOURCED_ERROR_FAIL)
479 return RESOURCED_ERROR_FAIL;
481 if (!strcmp("memps", appname) ||
482 !strcmp("crash-worker", appname) ||
483 !strcmp("system-syspopup", appname)) {
484 _E("%s(%d) was selected, skip it", appname, pid);
485 return RESOURCED_ERROR_FAIL;
490 resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
491 pid, NULL, NULL, PROC_TYPE_NONE);
493 if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
495 } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
496 int app_flag = pai->flags;
497 sigterm = app_flag & PROC_SIGTERM;
500 if (pai->memory.oom_killed)
503 pai->memory.oom_killed = true;
507 safe_kill(pid, SIGTERM);
509 safe_kill(pid, SIGKILL);
511 _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u KB, sigterm = %d\n",
512 flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
514 *victim_size = tsk->size;
516 if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
517 return RESOURCED_ERROR_NONE;
519 if (oom_popup_enable && !oom_popup) {
520 lowmem_launch_oompopup();
524 return RESOURCED_ERROR_NONE;
527 /* return LOWMEM_RECLAIM_CONT when killing should be continued */
528 static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
530 unsigned int available_mb;
533 * Processes with the priority higher than perceptible are killed
534 * only when the available memory is less than dynamic oom threshold.
536 if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
537 return LOWMEM_RECLAIM_CONT;
539 if (flags & (OOM_FORCE|OOM_SINGLE_SHOT)) {
540 _I("[LMK] %d is dropped during force kill, flag=%d",
542 return LOWMEM_RECLAIM_DROP;
544 available_mb = proc_get_mem_available();
545 if (available_mb > lmk_start_threshold_mb) {
546 _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
547 available_mb, lmk_start_threshold_mb);
548 return LOWMEM_RECLAIM_RETRY;
550 return LOWMEM_RECLAIM_CONT;
553 static int compare_victims(const struct task_info *ta, const struct task_info *tb)
560 * followed by kernel badness point calculation using heuristic.
561 * oom_score_adj is normalized by its unit, which varies -1000 ~ 1000.
563 pa = ta->oom_score_lru * (totalram_kb / 2000) + ta->size;
564 pb = tb->oom_score_lru * (totalram_kb / 2000) + tb->size;
569 static void lowmem_free_task_info_array(GArray *array)
573 for (i = 0; i < array->len; i++) {
574 struct task_info *tsk;
576 tsk = &g_array_index(array, struct task_info, i);
578 g_array_free(tsk->pids, true);
581 g_array_free(array, true);
584 static inline int is_dynamic_process_killer(int flags)
586 return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK);
589 static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres)
591 unsigned int available = proc_get_mem_available();
592 unsigned int should_be_freed_mb = 0;
594 if (available < thres)
595 should_be_freed_mb = thres - available;
597 * free THRESHOLD_MARGIN more than real should be freed,
598 * because launching app is consuming up the memory.
600 if (should_be_freed_mb > 0)
601 should_be_freed_mb += THRESHOLD_MARGIN;
605 return should_be_freed_mb;
608 static int lowmem_get_pids_proc(GArray *pids)
611 struct dirent *dentry;
613 dp = opendir("/proc");
615 _E("fail to open /proc");
616 return RESOURCED_ERROR_FAIL;
618 while ((dentry = readdir(dp)) != NULL) {
619 struct task_info tsk;
620 pid_t pid = 0, pgid = 0;
623 if (!isdigit(dentry->d_name[0]))
626 pid = (pid_t)atoi(dentry->d_name);
628 /* skip invalid pids or kernel processes */
638 if (proc_get_oom_score_adj(pid, &oom) < 0) {
639 _D("pid(%d) was already terminated", pid);
643 /* VIP pids should be excluded from the LMK list */
644 if (cgroup_get_type(oom) == CGROUP_VIP)
648 * Check whether this array includes applications or not.
649 * If it doesn't require to get applications
650 * and pid has been already included in pai,
653 if (oom > OOMADJ_SU && oom <= OOMADJ_APP_MAX)
657 * Currently, for tasks in the memory cgroup,
658 * do not consider multiple tasks with one pgid.
662 tsk.oom_score_adj = oom;
663 tsk.oom_score_lru = oom;
665 tsk.size = lowmem_get_task_mem_usage_rss(&tsk);
668 g_array_append_val(pids, tsk);
672 return RESOURCED_ERROR_NONE;
676 * @brief Terminate up to max_victims processes after finding them from pai.
677 It depends on proc_app_info lists
678 and it also reference systemservice cgroup
679 because some processes in this group don't have proc_app_info.
681 * @max_victims: max number of processes to be terminated
682 * @start_oom: find victims from start oom adj score value
683 * @end_oom: find victims to end oom adj score value
684 * @should_be_freed: amount of memory to be reclaimed (in MB)
685 * @total_size[out]: total size of possibly reclaimed memory (required)
686 * @completed: final outcome (optional)
687 * @threshold: desired value of memory available
689 static int lowmem_kill_victims(int max_victims,
690 int start_oom, int end_oom, unsigned should_be_freed, int flags,
691 unsigned int *total_size, int *completed, unsigned int threshold)
694 GSList *proc_app_list = NULL;
695 int i, ret, victim = 0;
696 unsigned int victim_size = 0;
697 unsigned int total_victim_size = 0;
698 int status = LOWMEM_RECLAIM_NONE;
699 GArray *candidates = NULL;
700 GSList *iter, *iterchild;
701 struct proc_app_info *pai = NULL;
703 int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
705 candidates = g_array_new(false, false, sizeof(struct task_info));
707 proc_app_list = proc_app_list_open();
708 gslist_for_each_item(iter, proc_app_list) {
712 pai = (struct proc_app_info *)iter->data;
716 oom_score_adj = pai->memory.oom_score_adj;
717 if (oom_score_adj > end_oom || oom_score_adj < start_oom)
720 if ((flags & OOM_REVISE) && pai->memory.oom_killed)
723 ti.pid = pai->main_pid;
724 ti.pgid = getpgid(ti.pid);
725 ti.oom_score_adj = oom_score_adj;
729 * Before oom_score_adj of favourite (oom_score = 270) applications is
730 * independent of lru_state, now we consider lru_state, while
731 * killing favourite process.
734 if (oom_score_adj == OOMADJ_FAVORITE && pai->lru_state >= PROC_BACKGROUND)
735 ti.oom_score_lru = OOMADJ_FAVORITE + OOMADJ_FAVORITE_APP_INCREASE * pai->lru_state;
737 ti.oom_score_lru = oom_score_adj;
740 ti.pids = g_array_new(false, false, sizeof(pid_t));
741 g_array_append_val(ti.pids, ti.pid);
742 gslist_for_each_item(iterchild, pai->childs) {
743 pid_t child = GPOINTER_TO_PID(iterchild->data);
744 g_array_append_val(ti.pids, child);
749 g_array_append_val(candidates, ti);
752 proc_app_list_close();
754 if (!candidates->len) {
755 status = LOWMEM_RECLAIM_NEXT_TYPE;
759 _D("[LMK] candidate ratio=%d/%d", candidates->len, total_count);
762 for (i = 0; i < candidates->len; i++) {
763 struct task_info *tsk;
765 tsk = &g_array_index(candidates, struct task_info, i);
766 tsk->size = lowmem_get_task_mem_usage_rss(tsk); /* KB */
770 * In case of start_oom == OOMADJ_SU,
771 * we're going to try to kill some of processes in /proc
772 * to handle low memory situation.
773 * It can find malicious system process even though it has low oom score.
775 if (start_oom == OOMADJ_SU)
776 lowmem_get_pids_proc(candidates);
778 g_array_sort(candidates, (GCompareFunc)compare_victims);
780 for (i = 0; i < candidates->len; i++) {
781 struct task_info *tsk;
783 if (i >= max_victims) {
784 status = LOWMEM_RECLAIM_NEXT_TYPE;
789 * Available memory is checking only every
790 * num_vict_between_check process for reducing burden.
792 if (!(i % num_vict_between_check)) {
793 if (proc_get_mem_available() > threshold) {
794 status = LOWMEM_RECLAIM_DONE;
799 if (!(flags & OOM_NOMEMORY_CHECK) &&
800 total_victim_size >= should_be_freed_kb) {
801 _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
802 victim, max_victims, total_victim_size);
803 status = LOWMEM_RECLAIM_DONE;
807 tsk = &g_array_index(candidates, struct task_info, i);
809 status = lowmem_check_kill_continued(tsk, flags);
810 if (status != LOWMEM_RECLAIM_CONT)
813 _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n", tsk->pid, tsk->oom_score_adj);
815 ret = lowmem_kill_victim(tsk, flags, i, &victim_size);
816 if (ret != RESOURCED_ERROR_NONE)
819 total_victim_size += victim_size;
823 lowmem_free_task_info_array(candidates);
824 *total_size = total_victim_size;
825 if(*completed != LOWMEM_RECLAIM_CONT)
828 *completed = LOWMEM_RECLAIM_NEXT_TYPE;
832 static int calculate_range_of_oom(enum cgroup_type type, int *min, int *max)
834 if (type == CGROUP_VIP || type >= CGROUP_END || type <= CGROUP_TOP) {
835 _E("cgroup type (%d) is out of scope", type);
836 return RESOURCED_ERROR_FAIL;
839 *max = cgroup_get_highest_oom_score_adj(type);
840 *min = cgroup_get_lowest_oom_score_adj(type);
842 return RESOURCED_ERROR_NONE;
845 static void lowmem_handle_request(struct lowmem_control *ctl)
847 int start_oom, end_oom;
848 int count = 0, victim_cnt = 0;
849 int max_victim_cnt = ctl->count;
850 int status = LOWMEM_RECLAIM_NONE;
851 unsigned int available_mb = 0;
852 unsigned int total_size_mb = 0;
853 unsigned int current_size = 0;
854 unsigned int reclaim_size_mb, shortfall_mb = 0;
855 enum cgroup_type cgroup_type = ctl->type;
857 available_mb = proc_get_mem_available();
858 reclaim_size_mb = ctl->size_mb > available_mb /* MB */
859 ? ctl->size_mb - available_mb : 0;
861 if (!reclaim_size_mb) {
862 status = LOWMEM_RECLAIM_DONE;
867 /* Prepare LMK to start doing it's job. Check preconditions. */
868 if (calculate_range_of_oom(cgroup_type, &start_oom, &end_oom))
871 lmk_start_threshold_mb = get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM];
872 shortfall_mb = is_memory_recovered(&available_mb, ctl->size_mb);
874 if (!shortfall_mb || !reclaim_size_mb) {
875 status = LOWMEM_RECLAIM_DONE;
881 victim_cnt = lowmem_kill_victims(max_victim_cnt, start_oom, end_oom,
882 reclaim_size_mb, ctl->flags, ¤t_size, &status, ctl->size_mb);
885 current_size = KBYTE_TO_MBYTE(current_size);
886 reclaim_size_mb -= reclaim_size_mb > current_size
887 ? current_size : reclaim_size_mb;
888 total_size_mb += current_size;
890 _I("[LMK] current: kill %d victims, reclaim_size=%uMB from %d to %d status=%s",
891 victim_cnt, current_size,
892 start_oom, end_oom, convert_status_to_str(status));
895 if ((status == LOWMEM_RECLAIM_DONE) ||
896 (status == LOWMEM_RECLAIM_DROP) ||
897 (status == LOWMEM_RECLAIM_RETRY))
901 * If it doesn't finish reclaiming memory in first operation,
902 - if flags has OOM_IN_DEPTH,
903 try to find victims again in the active cgroup.
904 otherwise, just return because there is no more victims in the desired cgroup.
905 - if flags has OOM_REVISE,
906 it means that resourced can't find victims from proc_app_list.
907 So, it should search victims or malicious process from /proc.
908 But searching /proc leads to abnormal behaviour.
909 (Make sluggish or kill same victims continuously)
910 Thus, otherwise, just return in first operation and wait some period.
912 if (cgroup_type == CGROUP_LOW) {
913 cgroup_type = CGROUP_MEDIUM;
915 } else if ((cgroup_type == CGROUP_MEDIUM) && (ctl->flags & OOM_IN_DEPTH)) {
916 cgroup_type = CGROUP_HIGH;
917 if(ctl->flags & OOM_FORCE)
918 max_victim_cnt = FOREGROUND_VICTIMS;
920 } else if ((cgroup_type == CGROUP_HIGH) && (ctl->flags & OOM_IN_DEPTH)) {
921 status = LOWMEM_RECLAIM_RETRY;
922 ctl->type = CGROUP_ROOT;
924 else if (cgroup_type == CGROUP_ROOT) {
925 status = LOWMEM_RECLAIM_RETRY;
928 _I("[LMK] Done: killed %d processes reclaimed=%uMB remaining=%uMB shortfall=%uMB status=%s",
929 count, total_size_mb, reclaim_size_mb, shortfall_mb, convert_status_to_str(status));
931 /* After we finish reclaiming it's worth to remove oldest memps logs */
932 ctl->status = status;
935 static void *lowmem_reclaim_worker(void *arg)
937 struct lowmem_worker *lmw = (struct lowmem_worker *)arg;
939 setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
941 g_async_queue_ref(lmw->queue);
945 struct lowmem_control *ctl;
947 LOWMEM_WORKER_IDLE(lmw);
948 /* Wait on any wake-up call */
949 ctl = g_async_queue_pop(lmw->queue);
951 if (ctl->flags & OOM_DROP)
952 LOWMEM_DESTROY_REQUEST(ctl);
954 if (!LOWMEM_WORKER_IS_ACTIVE(lmw) || !ctl)
957 LOWMEM_WORKER_RUN(lmw);
959 _D("[LMK] %d tries", ++try_count);
960 lowmem_handle_request(ctl);
962 * Case the process failed to reclaim requested amount of memory
963 * or still under have memory pressure - try the timeout wait.
964 * There is a chance this will get woken-up in a better reality.
966 if (ctl->status == LOWMEM_RECLAIM_RETRY &&
967 !(ctl->flags & OOM_SINGLE_SHOT)) {
968 unsigned int available_mb = proc_get_mem_available();
970 if (available_mb >= ctl->size_mb) {
971 _I("[LMK] Memory restored: requested=%uMB available=%uMB\n",
972 ctl->size_mb, available_mb);
973 ctl->status = LOWMEM_RECLAIM_DONE;
976 LOWMEM_DESTROY_REQUEST(ctl);
977 LOWMEM_WORKER_IDLE(lmw);
981 if (LOWMEM_WORKER_IS_ACTIVE(lmw)) {
982 g_usleep(LMW_RETRY_WAIT_TIMEOUT_MSEC);
983 ctl->flags |= OOM_REVISE;
989 * The ctl callback would check available size again.
990 * And it is last point in reclaiming worker.
991 * Resourced sent SIGKILL signal to victim processes
992 * so it should wait for a some seconds until each processes returns memory.
994 g_usleep(LMW_LOOP_WAIT_TIMEOUT_MSEC);
998 /* The lmk becomes the owner of all queued requests .. */
999 LOWMEM_DESTROY_REQUEST(ctl);
1000 LOWMEM_WORKER_IDLE(lmw);
1002 g_async_queue_unref(lmw->queue);
1006 static void change_lowmem_state(unsigned int mem_state)
1008 cur_mem_state = mem_state;
1009 lmk_start_threshold_mb = get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM];
1011 resourced_notify(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
1012 (void *)&cur_mem_state);
1015 /* only app can call this function
1016 * that is, service cannot call the function
1018 static void lowmem_swap_memory(char *path)
1020 unsigned int available_mb;
1022 if (cur_mem_state == MEM_LEVEL_HIGH)
1025 if (swap_get_state() != SWAP_ON)
1028 available_mb = proc_get_mem_available();
1029 if (cur_mem_state != MEM_LEVEL_LOW &&
1030 available_mb <= get_root_memcg_info()->threshold_mb[MEM_LEVEL_LOW])
1031 swap_activate_act();
1033 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
1034 memcg_swap_status = true;
1037 void lowmem_trigger_swap(pid_t pid, char *path, bool move)
1041 int lowest_oom_score_adj;
1044 _E("[SWAP] Unknown memory cgroup path to swap");
1048 /* In this case, corresponding process will be moved to memory CGROUP_LOW.
1051 error = proc_get_oom_score_adj(pid, &oom_score_adj);
1053 _E("[SWAP] Cannot get oom_score_adj of pid (%d)", pid);
1057 lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(CGROUP_LOW);
1059 if (oom_score_adj < lowest_oom_score_adj) {
1060 oom_score_adj = lowest_oom_score_adj;
1061 /* End of this funciton, 'lowmem_swap_memory()' funciton will be called */
1062 proc_set_oom_score_adj(pid, oom_score_adj, find_app_info(pid));
1067 /* Correponding process is already managed per app or service.
1068 * In addition, if some process is already located in the CGROUP_LOW, then just do swap
1070 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
1073 static void memory_level_send_system_event(int lv)
1079 case MEM_LEVEL_HIGH:
1080 case MEM_LEVEL_MEDIUM:
1082 str = EVT_VAL_MEMORY_NORMAL;
1084 case MEM_LEVEL_CRITICAL:
1085 str = EVT_VAL_MEMORY_SOFT_WARNING;
1088 str = EVT_VAL_MEMORY_HARD_WARNING;
1091 _E("Invalid state");
1095 b = bundle_create();
1097 _E("Failed to create bundle");
1101 bundle_add_str(b, EVT_KEY_LOW_MEMORY, str);
1102 eventsystem_send_system_event(SYS_EVENT_LOW_MEMORY, b);
1106 static void high_mem_act(void)
1110 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1112 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1113 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1114 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1115 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1116 memory_level_send_system_event(MEM_LEVEL_HIGH);
1119 change_lowmem_state(MEM_LEVEL_HIGH);
1121 if (swap_get_state() == SWAP_ON && memcg_swap_status) {
1122 resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, get_memcg_info(CGROUP_LOW));
1123 memcg_swap_status = false;
1125 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1126 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1127 (void *)CGROUP_FREEZER_ENABLED);
1130 static void swap_activate_act(void)
1134 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1136 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1138 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1139 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1140 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1141 memory_level_send_system_event(MEM_LEVEL_LOW);
1143 change_lowmem_state(MEM_LEVEL_LOW);
1144 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1145 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1146 (void *)CGROUP_FREEZER_ENABLED);
1148 if (swap_get_state() != SWAP_ON)
1149 resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
1152 static void dedup_act(enum ksm_scan_mode mode)
1157 if (dedup_get_state() != DEDUP_ONE_SHOT)
1160 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1161 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1162 (void *)CGROUP_FREEZER_ENABLED);
1164 if (mode == KSM_SCAN_PARTIAL) {
1165 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1167 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1169 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1170 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1171 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1172 memory_level_send_system_event(MEM_LEVEL_MEDIUM);
1174 change_lowmem_state(MEM_LEVEL_MEDIUM);
1176 data = KSM_SCAN_PARTIAL;
1177 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
1178 } else if (mode == KSM_SCAN_FULL) {
1179 data = KSM_SCAN_FULL;
1180 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
1184 static void swap_compact_act(void)
1186 change_lowmem_state(MEM_LEVEL_CRITICAL);
1187 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_CRITICAL);
1188 memory_level_send_system_event(MEM_LEVEL_CRITICAL);
1191 static void medium_cb(struct lowmem_control *ctl)
1193 if (ctl->status == LOWMEM_RECLAIM_DONE)
1195 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
1198 static void lmk_act(void)
1200 unsigned int available_mb;
1202 int status = VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL;
1205 * Don't trigger reclaim worker
1206 * if it is already running
1208 if (LOWMEM_WORKER_IS_RUNNING(&lmw))
1211 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1213 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1215 memory_level_send_system_event(MEM_LEVEL_OOM);
1216 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING) {
1217 if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
1218 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1219 (void *)CGROUP_FREEZER_PAUSED);
1220 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1221 VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
1223 available_mb = proc_get_mem_available();
1225 change_lowmem_state(MEM_LEVEL_OOM);
1227 if (available_mb < get_root_memcg_info()->threshold_leave_mb) {
1228 struct lowmem_control *ctl;
1230 ctl = LOWMEM_NEW_REQUEST();
1232 LOWMEM_SET_REQUEST(ctl, OOM_IN_DEPTH,
1233 CGROUP_LOW, get_root_memcg_info()->threshold_leave_mb,
1234 num_max_victims, medium_cb);
1235 lowmem_queue_request(&lmw, ctl);
1239 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_OOM);
1242 * Flush resourced memory such as other processes.
1243 * Resourced can use both many fast bins and sqlite3 cache memery.
1250 static void lowmem_trigger_memory_state_action(int mem_state)
1253 * Check if the state we want to set is different from current
1254 * But it should except this condition if mem_state is already medium.
1255 * Otherwise, recalim worker couldn't run any more.
1257 if (mem_state != MEM_LEVEL_OOM && cur_mem_state == mem_state)
1260 switch (mem_state) {
1261 case MEM_LEVEL_HIGH:
1264 case MEM_LEVEL_MEDIUM:
1265 dedup_act(KSM_SCAN_PARTIAL);
1268 swap_activate_act();
1270 case MEM_LEVEL_CRITICAL:
1271 dedup_act(KSM_SCAN_FULL);
1282 static unsigned int check_mem_state(unsigned int available_mb)
1285 for (mem_state = MEM_LEVEL_MAX - 1; mem_state > MEM_LEVEL_HIGH; mem_state--) {
1286 if (mem_state != MEM_LEVEL_OOM &&
1287 available_mb <= get_root_memcg_info()->threshold_mb[mem_state])
1289 else if (mem_state == MEM_LEVEL_OOM && available_mb <= lmk_start_threshold_mb)
1296 /* setup memcg parameters depending on total ram size. */
1297 static void setup_memcg_params(void)
1299 unsigned long total_ramsize_mb;
1302 total_ramsize_mb = BYTE_TO_MBYTE(totalram_bytes);
1304 _D("Total: %lu MB", total_ramsize_mb);
1305 if (total_ramsize_mb <= MEM_SIZE_64) {
1306 /* set thresholds for ram size 64M */
1307 proactive_threshold_mb = PROACTIVE_64_THRES;
1308 proactive_leave_mb = PROACTIVE_64_LEAVE;
1309 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_64_THRES_DEDUP);
1310 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_64_THRES_SWAP);
1311 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_64_THRES_LOW);
1312 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_64_THRES_MEDIUM);
1313 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_64_THRES_LEAVE);
1314 num_max_victims = CGROUP_ROOT_64_NUM_VICTIMS;
1315 } else if (total_ramsize_mb <= MEM_SIZE_256) {
1316 /* set thresholds for ram size 256M */
1317 proactive_threshold_mb = PROACTIVE_256_THRES;
1318 proactive_leave_mb = PROACTIVE_256_LEAVE;
1319 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_256_THRES_DEDUP);
1320 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_256_THRES_SWAP);
1321 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_256_THRES_LOW);
1322 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_256_THRES_MEDIUM);
1323 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_256_THRES_LEAVE);
1324 num_max_victims = CGROUP_ROOT_256_NUM_VICTIMS;
1325 } else if (total_ramsize_mb <= MEM_SIZE_448) {
1326 /* set thresholds for ram size 448M */
1327 proactive_threshold_mb = PROACTIVE_448_THRES;
1328 proactive_leave_mb = PROACTIVE_448_LEAVE;
1329 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_448_THRES_DEDUP);
1330 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_448_THRES_SWAP);
1331 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_448_THRES_LOW);
1332 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_448_THRES_MEDIUM);
1333 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_448_THRES_LEAVE);
1334 num_max_victims = CGROUP_ROOT_448_NUM_VICTIMS;
1335 } else if (total_ramsize_mb <= MEM_SIZE_512) {
1336 /* set thresholds for ram size 512M */
1337 proactive_threshold_mb = PROACTIVE_512_THRES;
1338 proactive_leave_mb = PROACTIVE_512_LEAVE;
1339 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_512_THRES_DEDUP);
1340 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_512_THRES_SWAP);
1341 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_512_THRES_LOW);
1342 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_512_THRES_MEDIUM);
1343 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_512_THRES_LEAVE);
1344 num_max_victims = CGROUP_ROOT_512_NUM_VICTIMS;
1345 } else if (total_ramsize_mb <= MEM_SIZE_768) {
1346 /* set thresholds for ram size 512M */
1347 proactive_threshold_mb = PROACTIVE_768_THRES;
1348 proactive_leave_mb = PROACTIVE_768_LEAVE;
1349 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_768_THRES_DEDUP);
1350 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_768_THRES_SWAP);
1351 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_768_THRES_LOW);
1352 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_768_THRES_MEDIUM);
1353 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_768_THRES_LEAVE);
1354 num_max_victims = CGROUP_ROOT_768_NUM_VICTIMS;
1355 } else if (total_ramsize_mb <= MEM_SIZE_1024) {
1356 /* set thresholds for ram size more than 1G */
1357 proactive_threshold_mb = PROACTIVE_1024_THRES;
1358 proactive_leave_mb = PROACTIVE_1024_LEAVE;
1359 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_1024_THRES_DEDUP);
1360 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_1024_THRES_SWAP);
1361 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_1024_THRES_LOW);
1362 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_1024_THRES_MEDIUM);
1363 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_1024_THRES_LEAVE);
1364 num_max_victims = CGROUP_ROOT_1024_NUM_VICTIMS;
1365 } else if (total_ramsize_mb <= MEM_SIZE_2048) {
1366 proactive_threshold_mb = PROACTIVE_2048_THRES;
1367 proactive_leave_mb = PROACTIVE_2048_LEAVE;
1368 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_2048_THRES_DEDUP);
1369 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_2048_THRES_SWAP);
1370 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_2048_THRES_LOW);
1371 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_2048_THRES_MEDIUM);
1372 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_2048_THRES_LEAVE);
1373 num_max_victims = CGROUP_ROOT_2048_NUM_VICTIMS;
1375 proactive_threshold_mb = PROACTIVE_3072_THRES;
1376 proactive_leave_mb = PROACTIVE_3072_LEAVE;
1377 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_3072_THRES_DEDUP);
1378 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_3072_THRES_SWAP);
1379 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_3072_THRES_LOW);
1380 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_3072_THRES_MEDIUM);
1381 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_3072_THRES_LEAVE);
1382 num_max_victims = CGROUP_ROOT_3072_NUM_VICTIMS;
1386 static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
1388 int cur_oom_score_adj;
1390 struct memcg_info *mi;
1391 int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
1393 if(next_memcg_idx < CGROUP_VIP || next_memcg_idx > CGROUP_LOW) {
1394 _E("cgroup type (%d) should not be called", next_memcg_idx);
1397 mi = get_memcg_info(next_memcg_idx);
1404 cgroup_write_pid_fullpath(mi->name, pid);
1409 if (pai->main_pid == pid) {
1410 cur_oom_score_adj = pai->memory.oom_score_adj;
1411 cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
1413 /* This pid is not yet registered at the memory cgroup.
1414 * plz, reference proc_create_app_info function
1416 if (cur_oom_score_adj != OOMADJ_APP_MAX + 10) {
1417 /* VIP processes should not be asked to move. */
1418 if (cur_memcg_idx <= CGROUP_VIP) {
1419 _E("[MEMORY-CGROUP] current cgroup (%s) cannot be VIP or Root", convert_cgroup_type_to_str(cur_memcg_idx));
1424 _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));
1426 if (cur_oom_score_adj == next_oom_score_adj) {
1427 _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
1431 proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
1433 if (!lowmem_limit_move_cgroup(pai))
1436 if(cur_memcg_idx == next_memcg_idx)
1439 cgroup_write_pid_fullpath(mi->name, pid);
1440 if (next_memcg_idx == CGROUP_LOW)
1441 lowmem_swap_memory(get_memcg_info(CGROUP_LOW)->name);
1445 if (pai->memory.use_mem_limit)
1448 cgroup_write_pid_fullpath(mi->name, pid);
1452 static int lowmem_activate_worker(void)
1454 int ret = RESOURCED_ERROR_NONE;
1456 if (LOWMEM_WORKER_IS_ACTIVE(&lmw)) {
1460 lmw.queue = g_async_queue_new_full(lowmem_request_destroy);
1462 _E("Failed to create request queue\n");
1463 return RESOURCED_ERROR_FAIL;
1465 LOWMEM_WORKER_ACTIVATE(&lmw);
1466 ret = pthread_create(&lmw.worker_thread, NULL,
1467 (void *)lowmem_reclaim_worker, (void *)&lmw);
1469 LOWMEM_WORKER_DEACTIVATE(&lmw);
1470 _E("Failed to create LMK thread: %d\n", ret);
1472 pthread_detach(lmw.worker_thread);
1473 ret = RESOURCED_ERROR_NONE;
1478 static void lowmem_deactivate_worker(void)
1480 struct lowmem_control *ctl;
1482 if (!LOWMEM_WORKER_IS_ACTIVE(&lmw))
1485 LOWMEM_WORKER_DEACTIVATE(&lmw);
1486 lowmem_drain_queue(&lmw);
1488 ctl = LOWMEM_NEW_REQUEST();
1490 _E("Critical - g_slice alloc failed - Lowmem cannot be deactivated");
1493 ctl->flags = OOM_DROP;
1494 g_async_queue_push(lmw.queue, ctl);
1495 g_async_queue_unref(lmw.queue);
1498 static int lowmem_press_eventfd_read(int fd)
1500 unsigned long long dummy_state;
1502 return read(fd, &dummy_state, sizeof(dummy_state));
1505 static void lowmem_press_root_cgroup_handler(void)
1507 static unsigned int prev_available_mb;
1508 unsigned int available_mb;
1511 available_mb = proc_get_mem_available();
1512 if (prev_available_mb == available_mb)
1515 mem_state = check_mem_state(available_mb);
1516 lowmem_trigger_memory_state_action(mem_state);
1517 prev_available_mb = available_mb;
1520 static bool lowmem_press_eventfd_handler(int fd, void *data)
1522 struct memcg_info *mi;
1523 enum cgroup_type type = CGROUP_ROOT;
1525 // FIXME: probably shouldn't get ignored
1526 if (lowmem_press_eventfd_read(fd) < 0)
1527 _E("Failed to read lowmem press event, %m\n");
1529 for (type = CGROUP_ROOT; type < CGROUP_END; type++) {
1530 if (!get_cgroup_tree(type) || !get_memcg_info(type))
1532 mi = get_memcg_info(type);
1533 if (fd == mi->evfd) {
1534 /* call low memory handler for this memcg */
1535 if (type == CGROUP_ROOT) {
1536 lowmem_press_root_cgroup_handler();
1540 _E("Wrong event fd for cgroup %s", convert_cgroup_type_to_str(type));
1549 static int lowmem_press_register_eventfd(struct memcg_info *mi)
1552 const char *name = mi->name;
1553 static fd_handler_h handler;
1555 if (mi->threshold_mb[MEM_LEVEL_OOM] == LOWMEM_THRES_INIT)
1558 evfd = memcg_set_eventfd(name, MEMCG_EVENTFD_MEMORY_PRESSURE,
1562 int saved_errno = errno;
1563 _E("Failed to register event press fd %s cgroup", name);
1564 return -saved_errno;
1569 add_fd_read_handler(evfd, lowmem_press_eventfd_handler, NULL, NULL, &handler);
1573 static int lowmem_press_setup_eventfd(void)
1577 for (i = CGROUP_ROOT; i < CGROUP_END; i++) {
1578 if (!get_use_hierarchy(i))
1581 lowmem_press_register_eventfd(get_memcg_info(i));
1583 return RESOURCED_ERROR_NONE;
1586 static void lowmem_force_reclaim_cb(struct lowmem_control *ctl)
1588 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
1591 int lowmem_trigger_reclaim(int flags, int victims, enum cgroup_type type, int threshold_mb)
1593 struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
1598 flags |= OOM_FORCE | OOM_IN_DEPTH | OOM_SINGLE_SHOT;
1599 victims = victims > 0 ? victims : MAX_MEMORY_CGROUP_VICTIMS;
1600 type = type > 0 ? type : CGROUP_LOW;
1601 threshold_mb = threshold_mb > 0 ? threshold_mb : get_root_memcg_info()->threshold_leave_mb;
1603 lowmem_change_memory_state(MEM_LEVEL_CRITICAL, 1);
1604 LOWMEM_SET_REQUEST(ctl, flags,
1605 type, threshold_mb, victims,
1606 lowmem_force_reclaim_cb);
1607 lowmem_queue_request(&lmw, ctl);
1612 void lowmem_trigger_swap_reclaim(enum cgroup_type type, unsigned long long swap_size_bytes)
1614 int size_mb, victims;
1616 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1617 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1619 size_mb = get_root_memcg_info()->threshold_leave_mb + BYTE_TO_MBYTE(swap_size_bytes);
1620 lowmem_trigger_reclaim(0, victims, type, size_mb);
1623 bool lowmem_fragmentated(void)
1625 struct buddyinfo bi;
1628 ret = proc_get_buddyinfo("Normal", &bi);
1633 * The fragmentation_size is the minimum count of order-2 pages in "Normal" zone.
1634 * If total buddy pages is smaller than fragmentation_size,
1635 * resourced will detect kernel memory is fragmented.
1636 * Default value is zero in low memory device.
1638 if (bi.page[PAGE_32K] + (bi.page[PAGE_64K] << 1) + (bi.page[PAGE_128K] << 2) +
1639 (bi.page[PAGE_256K] << 3) < fragmentation_size) {
1640 _I("fragmentation detected, need to execute proactive oom killer");
1646 static void lowmem_proactive_oom_killer(int flags, char *appid)
1648 unsigned int before_mb;
1651 before_mb = proc_get_mem_available();
1653 /* If memory state is medium or normal, just return and kill in oom killer */
1654 if (before_mb < get_root_memcg_info()->threshold_mb[MEM_LEVEL_OOM] ||
1655 before_mb > proactive_leave_mb)
1658 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1659 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1661 #ifdef HEART_SUPPORT
1663 * This branch is used only when HEART module is compiled in and
1664 * it's MEMORY module must be enabled. Otherwise this is skipped.
1666 struct heart_memory_data *md = heart_memory_get_memdata(appid, DATA_LATEST);
1668 unsigned int rss_mb, after_mb, size_mb;
1670 rss_mb = KBYTE_TO_MBYTE(md->avg_rss);
1674 after_mb = before_mb - rss_mb;
1676 * after launching app, ensure that available memory is
1677 * above threshold_leave
1679 if (after_mb >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1682 if (proactive_threshold_mb - rss_mb >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1683 size_mb = proactive_threshold_mb;
1685 size_mb = rss_mb + get_root_memcg_info()->threshold[MEM_LEVEL_OOM] + THRESHOLD_MARGIN;
1687 _D("history based proactive LMK : avg rss %u, available %u required = %u MB",
1688 rss_mb, before_mb, size_mb);
1689 lowmem_trigger_reclaim(0, victims, CGROUP_LOW, size_mb);
1696 * When there is no history data for the launching app,
1697 * it is necessary to check current fragmentation state or application manifest file.
1698 * So, resourced feels proactive LMK is required, run oom killer based on dynamic
1701 if (lowmem_fragmentated())
1705 * run proactive oom killer only when available is larger than
1706 * dynamic process threshold
1708 if (!proactive_threshold_mb || before_mb >= proactive_threshold_mb)
1711 if (!(flags & PROC_LARGEMEMORY))
1716 * free THRESHOLD_MARGIN more than real should be freed,
1717 * because launching app is consuming up the memory.
1719 _D("Run threshold based proactive LMK: memory level to reach: %u MB\n",
1720 proactive_leave_mb + THRESHOLD_MARGIN);
1721 lowmem_trigger_reclaim(0, victims, CGROUP_LOW, proactive_leave_mb + THRESHOLD_MARGIN);
1724 unsigned int lowmem_get_proactive_thres(void)
1726 return proactive_threshold_mb;
1729 static int lowmem_prelaunch_handler(void *data)
1731 struct proc_status *ps = (struct proc_status *)data;
1732 struct proc_app_info *pai = ps->pai;
1734 if (!pai || CHECK_BIT(pai->flags, PROC_SERVICEAPP))
1735 return RESOURCED_ERROR_NONE;
1737 lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid);
1738 return RESOURCED_ERROR_NONE;
1741 int lowmem_control_handler(void *data)
1743 struct lowmem_control_data *lowmem_data;
1745 lowmem_data = (struct lowmem_control_data *)data;
1746 switch (lowmem_data->control_type) {
1747 case LOWMEM_MOVE_CGROUP:
1748 lowmem_move_memcgroup((pid_t)lowmem_data->pid,
1749 lowmem_data->oom_score_adj, lowmem_data->pai);
1754 return RESOURCED_ERROR_NONE;
1757 static inline int calculate_threshold_size(double ratio)
1759 unsigned long long size_bytes = (double)totalram_bytes * ratio / 100.0;
1760 return BYTE_TO_MBYTE(size_bytes);
1763 static void load_configs(const char *path)
1765 struct memcg_conf *memcg_conf = get_memcg_conf();
1767 /* set MemoryGroupLimit section */
1768 for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
1769 if (memcg_conf->cgroup_limit[cgroup] > 0.0)
1770 memcg_info_set_limit(get_memcg_info(cgroup),
1771 memcg_conf->cgroup_limit[cgroup]/100.0, totalram_bytes);
1774 /* set MemoryLevelThreshold section */
1775 for (int lvl = MEM_LEVEL_MEDIUM; lvl < MEM_LEVEL_MAX; lvl++) {
1776 if (memcg_conf->threshold[lvl].percent &&
1777 memcg_conf->threshold[lvl].threshold > 0) {
1778 memcg_set_threshold(CGROUP_ROOT, lvl,
1779 calculate_threshold_size(memcg_conf->threshold[lvl].threshold));
1781 if (lvl == MEM_LEVEL_OOM)
1782 memcg_set_leave_threshold(CGROUP_ROOT,
1783 get_memcg_info(CGROUP_ROOT)->threshold_mb[lvl] * 2);
1785 else if (memcg_conf->threshold[lvl].threshold > 0) {
1786 memcg_set_threshold(CGROUP_ROOT, lvl,
1787 memcg_conf->threshold[lvl].threshold);
1789 if (lvl == MEM_LEVEL_OOM)
1790 memcg_set_leave_threshold(CGROUP_ROOT,
1791 get_memcg_info(CGROUP_ROOT)->threshold_mb[lvl] * 2);
1794 oom_popup_enable = memcg_conf->oom_popup;
1796 /* set MemoryAppTypeLimit and MemoryAppStatusLimit section */
1797 lowmem_memory_init(memcg_conf->service.memory_bytes, memcg_conf->widget.memory_bytes,
1798 memcg_conf->guiapp.memory_bytes, memcg_conf->background.memory_bytes);
1799 lowmem_action_init(memcg_conf->service.action, memcg_conf->widget.action,
1800 memcg_conf->guiapp.action, memcg_conf->background.action);
1805 static void print_mem_configs(void)
1807 /* print info of Memory section */
1808 for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
1809 _I("[MEMORY-CGROUP] set memory for cgroup '%s' to %llu bytes",
1810 convert_cgroup_type_to_str(cgroup), get_memcg_info(cgroup)->limit_bytes);
1813 for (int cgroup = CGROUP_ROOT; cgroup < CGROUP_END; cgroup++) {
1814 for (int mem_lvl = 0; mem_lvl < MEM_LEVEL_MAX; mem_lvl++) {
1815 _I("[MEMORY-LEVEL] set threshold of %s for memory level '%s' to %u MB", convert_cgroup_type_to_str(cgroup),
1816 convert_memstate_to_str(mem_lvl), get_memcg_info(cgroup)->threshold_mb[mem_lvl]);
1820 _I("[LMK] set number of max victims as %d", num_max_victims);
1821 _I("[LMK] set threshold leave to %u MB", get_root_memcg_info()->threshold_leave_mb);
1822 _I("[LMK] set proactive threshold to %u MB", proactive_threshold_mb);
1823 _I("[LMK] set proactive low memory killer leave to %u MB", proactive_leave_mb);
1825 /* print info of POPUP section */
1826 _I("[POPUP] oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
1829 #include "file-helper.h"
1831 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
1832 static int lowmem_init(void)
1834 int ret = RESOURCED_ERROR_NONE;
1836 _D("resourced memory init start");
1839 ret = cgroup_make_full_subdir(MEMCG_PATH);
1840 ret_value_msg_if(ret < 0, ret, "memory cgroup init failed\n");
1841 memcg_params_init();
1843 setup_memcg_params();
1845 /* default configuration */
1846 load_configs(MEM_CONF_FILE);
1848 /* this function should be called after parsing configurations */
1849 memcg_write_limiter_params();
1850 print_mem_configs();
1852 /* make a worker thread called low memory killer */
1853 ret = lowmem_activate_worker();
1855 _E("[LMK] oom thread create failed\n");
1859 /* register threshold and event fd */
1860 ret = lowmem_press_setup_eventfd();
1862 _E("[MEMORY-LIMIT] eventfd setup failed");
1867 lowmem_limit_init();
1868 lowmem_system_init();
1870 register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1871 register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1876 static int lowmem_exit(void)
1878 if (strncmp(event_level, MEMCG_DEFAULT_EVENT_LEVEL, sizeof(MEMCG_DEFAULT_EVENT_LEVEL)))
1881 lowmem_deactivate_worker();
1882 lowmem_limit_exit();
1883 lowmem_system_exit();
1885 unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1886 unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1888 return RESOURCED_ERROR_NONE;
1891 static int resourced_memory_init(void *data)
1893 lowmem_ops = &memory_modules_ops;
1894 return lowmem_init();
1897 static int resourced_memory_finalize(void *data)
1899 return lowmem_exit();
1902 void lowmem_change_memory_state(int state, int force)
1909 unsigned int available_mb = proc_get_mem_available();
1910 mem_state = check_mem_state(available_mb);
1913 lowmem_trigger_memory_state_action(mem_state);
1916 unsigned long lowmem_get_ktotalram(void)
1921 unsigned long long lowmem_get_totalram(void)
1923 return totalram_bytes;
1926 void lowmem_restore_memcg(struct proc_app_info *pai)
1930 struct cgroup *cgroup = NULL;
1931 struct memcg_info *mi = NULL;
1932 pid_t pid = pai->main_pid;
1934 ret = cgroup_pid_get_path("memory", pid, &cgpath);
1938 for (index = CGROUP_END-1; index >= CGROUP_ROOT; index--) {
1939 cgroup = get_cgroup_tree(index);
1943 mi = cgroup->memcg_info;
1947 if (!strcmp(cgroup->hashname, ""))
1949 if (strstr(cgpath, cgroup->hashname))
1952 pai->memory.memcg_idx = index;
1953 pai->memory.memcg_info = mi;
1954 if(strstr(cgpath, pai->appid))
1955 pai->memory.use_mem_limit = true;
1960 static struct module_ops memory_modules_ops = {
1961 .priority = MODULE_PRIORITY_HIGH,
1963 .init = resourced_memory_init,
1964 .exit = resourced_memory_finalize,
1967 MODULE_REGISTER(&memory_modules_ops)