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;
183 static unsigned proactive_leave;
184 static unsigned lmk_start_threshold;
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)*/
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 = __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 static void memory_cgroup_proactive_lmk_act(enum cgroup_type type, struct memcg_info *mi);
347 /* low memory action function */
348 static void high_mem_act(void);
349 static void swap_activate_act(void);
350 static void swap_compact_act(void);
351 static void lmk_act(void);
354 static size_t cur_mem_state = MEM_LEVEL_HIGH;
355 static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
356 static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
358 static unsigned long totalram;
359 static unsigned long ktotalram;
361 static struct module_ops memory_modules_ops;
362 static const struct module_ops *lowmem_ops;
363 static bool oom_popup_enable;
364 static bool oom_popup;
365 static bool memcg_swap_status;
366 static bool bg_reclaim;
367 static int fragmentation_size;
369 static const char *convert_cgroup_type_to_str(int type)
371 static const char *type_table[] =
372 {"/", "VIP", "High", "Medium", "Lowest"};
373 if (type >= CGROUP_ROOT && type <= CGROUP_LOW)
374 return type_table[type];
379 static const char *convert_status_to_str(int status)
381 static const char *status_table[] =
382 {"none", "done", "drop", "cont", "retry", "next_type"};
383 if(status >= LOWMEM_RECLAIM_NONE && status <= LOWMEM_RECLAIM_NEXT_TYPE)
384 return status_table[status];
385 return "error status";
388 static const char *convert_memstate_to_str(int mem_state)
390 static const char *state_table[] = {"mem high", "mem medium",
391 "mem low", "mem critical", "mem oom",};
392 if (mem_state >= 0 && mem_state < MEM_LEVEL_MAX)
393 return state_table[mem_state];
397 static int lowmem_launch_oompopup(void)
399 GVariantBuilder *const gv_builder = g_variant_builder_new(G_VARIANT_TYPE("a{ss}"));
400 g_variant_builder_add(gv_builder, "{ss}", "_SYSPOPUP_CONTENT_", "lowmemory_oom");
402 GVariant *const params = g_variant_new("(a{ss})", gv_builder);
403 g_variant_builder_unref(gv_builder);
405 int ret = d_bus_call_method_sync_gvariant(SYSTEM_POPUP_BUS_NAME,
406 SYSTEM_POPUP_PATH_SYSTEM, SYSTEM_POPUP_IFACE_SYSTEM,
407 "PopupLaunch", params);
409 g_variant_unref(params);
414 static inline void get_total_memory(void)
421 totalram = si.totalram;
422 ktotalram = BYTE_TO_KBYTE(totalram);
426 static int lowmem_mem_usage_uss(pid_t pid, unsigned int *usage)
428 unsigned int uss, zram = 0;
434 * In lowmem we need to know memory size of processes to
435 * for terminating apps. To get most real value of usage
436 * we should use USS + ZRAM usage for selected process.
438 * Those values will contain the most approximated amount
439 * of memory that will be freed after process termination.
441 ret = proc_get_uss(pid, &uss);
442 if (ret != RESOURCED_ERROR_NONE)
445 if (swap_get_state() == SWAP_ON) {
446 ret = proc_get_zram_usage(pid, &zram);
447 /* If we don't get zram usage, it's not a problem */
448 if (ret != RESOURCED_ERROR_NONE)
452 return RESOURCED_ERROR_NONE;
455 unsigned int lowmem_get_task_mem_usage_rss(const struct task_info *tsk)
457 unsigned int size = 0, total_size = 0;
462 * If pids are allocated only when there are multiple processes with
463 * the same pgid e.g., browser and web process. Mostly, single process
466 if (tsk->pids == NULL) {
467 ret = proc_get_ram_usage(tsk->pid, &size);
469 /* If there is no proc entry for given pid the process
470 * should be abandoned during further processing
473 _D("failed to get rss memory usage of %d", tsk->pid);
478 for (index = 0; index < tsk->pids->len; index++) {
479 pid = g_array_index(tsk->pids, pid_t, index);
480 ret = proc_get_ram_usage(pid, &size);
481 if (ret != RESOURCED_ERROR_NONE)
489 static int lowmem_kill_victim(const struct task_info *tsk,
490 int flags, int memps_log, unsigned int *victim_size)
494 char appname[PATH_MAX];
496 struct proc_app_info *pai;
500 if (pid <= 0 || pid == getpid())
501 return RESOURCED_ERROR_FAIL;
503 ret = proc_get_cmdline(pid, appname, sizeof appname);
504 if (ret == RESOURCED_ERROR_FAIL)
505 return RESOURCED_ERROR_FAIL;
507 if (!strcmp("memps", appname) ||
508 !strcmp("crash-worker", appname) ||
509 !strcmp("system-syspopup", appname)) {
510 _E("%s(%d) was selected, skip it", appname, pid);
511 return RESOURCED_ERROR_FAIL;
516 resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
517 pid, NULL, NULL, PROC_TYPE_NONE);
519 if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
521 } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
522 int app_flag = pai->flags;
523 sigterm = app_flag & PROC_SIGTERM;
526 if (pai->memory.oom_killed)
529 pai->memory.oom_killed = true;
533 safe_kill(pid, SIGTERM);
535 safe_kill(pid, SIGKILL);
537 _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u, sigterm = %d\n",
538 flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
540 *victim_size = tsk->size;
542 if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
543 return RESOURCED_ERROR_NONE;
545 if (oom_popup_enable && !oom_popup) {
546 lowmem_launch_oompopup();
550 return RESOURCED_ERROR_NONE;
553 /* return LOWMEM_RECLAIM_CONT when killing should be continued */
554 static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
556 unsigned int available;
559 * Processes with the priority higher than perceptible are killed
560 * only when the available memory is less than dynamic oom threshold.
562 if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
563 return LOWMEM_RECLAIM_CONT;
565 if (flags & (OOM_FORCE|OOM_SINGLE_SHOT)) {
566 _I("[LMK] %d is dropped during force kill, flag=%d",
568 return LOWMEM_RECLAIM_DROP;
570 available = proc_get_mem_available();
571 if (available > lmk_start_threshold) {
572 _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
573 available, lmk_start_threshold);
574 return LOWMEM_RECLAIM_RETRY;
576 return LOWMEM_RECLAIM_CONT;
579 static int compare_victims(const struct task_info *ta, const struct task_info *tb)
586 * followed by kernel badness point calculation using heuristic.
587 * oom_score_adj is normalized by its unit, which varies -1000 ~ 1000.
589 pa = ta->oom_score_lru * (ktotalram / 2000) + ta->size;
590 pb = tb->oom_score_lru * (ktotalram / 2000) + tb->size;
595 static void lowmem_free_task_info_array(GArray *array)
599 for (i = 0; i < array->len; i++) {
600 struct task_info *tsk;
602 tsk = &g_array_index(array, struct task_info, i);
604 g_array_free(tsk->pids, true);
607 g_array_free(array, true);
610 static inline int is_dynamic_process_killer(int flags)
612 return (flags & OOM_FORCE) && !(flags & OOM_NOMEMORY_CHECK);
615 static unsigned int is_memory_recovered(unsigned int *avail, unsigned int thres)
617 unsigned int available = proc_get_mem_available();
618 unsigned int should_be_freed = 0;
620 if (available < thres)
621 should_be_freed = thres - available;
623 * free THRESHOLD_MARGIN more than real should be freed,
624 * because launching app is consuming up the memory.
626 if (should_be_freed > 0)
627 should_be_freed += THRESHOLD_MARGIN;
631 return should_be_freed;
634 static int lowmem_get_pids_proc(GArray *pids)
637 struct dirent *dentry;
639 dp = opendir("/proc");
641 _E("fail to open /proc");
642 return RESOURCED_ERROR_FAIL;
644 while ((dentry = readdir(dp)) != NULL) {
645 struct task_info tsk;
646 pid_t pid = 0, pgid = 0;
649 if (!isdigit(dentry->d_name[0]))
652 pid = (pid_t)atoi(dentry->d_name);
654 /* skip invalid pids or kernel processes */
664 if (proc_get_oom_score_adj(pid, &oom) < 0) {
665 _D("pid(%d) was already terminated", pid);
669 /* VIP pids should be excluded from the LMK list */
670 if (cgroup_get_type(oom) == CGROUP_VIP)
674 * Check whether this array includes applications or not.
675 * If it doesn't require to get applications
676 * and pid has been already included in pai,
679 if (oom > OOMADJ_SU && oom <= OOMADJ_APP_MAX)
683 * Currently, for tasks in the memory cgroup,
684 * do not consider multiple tasks with one pgid.
688 tsk.oom_score_adj = oom;
689 tsk.oom_score_lru = oom;
691 tsk.size = lowmem_get_task_mem_usage_rss(&tsk);
694 g_array_append_val(pids, tsk);
698 return RESOURCED_ERROR_NONE;
702 * @brief Terminate up to max_victims processes after finding them from pai.
703 It depends on proc_app_info lists
704 and it also reference systemservice cgroup
705 because some processes in this group don't have proc_app_info.
707 * @max_victims: max number of processes to be terminated
708 * @start_oom: find victims from start oom adj score value
709 * @end_oom: find victims to end oom adj score value
710 * @should_be_freed: amount of memory to be reclaimed (in MB)
711 * @total_size[out]: total size of possibly reclaimed memory (required)
712 * @completed: final outcome (optional)
713 * @threshold: desired value of memory available
715 static int lowmem_kill_victims(int max_victims,
716 int start_oom, int end_oom, unsigned should_be_freed, int flags,
717 unsigned int *total_size, int *completed, int threshold)
720 GSList *proc_app_list = NULL;
721 int i, ret, victim = 0;
722 unsigned int victim_size = 0;
723 unsigned int total_victim_size = 0;
724 int status = LOWMEM_RECLAIM_NONE;
725 GArray *candidates = NULL;
726 GSList *iter, *iterchild;
727 struct proc_app_info *pai = NULL;
729 int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
731 candidates = g_array_new(false, false, sizeof(struct task_info));
733 proc_app_list = proc_app_list_open();
734 gslist_for_each_item(iter, proc_app_list) {
738 pai = (struct proc_app_info *)iter->data;
742 oom_score_adj = pai->memory.oom_score_adj;
743 if (oom_score_adj > end_oom || oom_score_adj < start_oom)
746 if ((flags & OOM_REVISE) && pai->memory.oom_killed)
749 ti.pid = pai->main_pid;
750 ti.pgid = getpgid(ti.pid);
751 ti.oom_score_adj = oom_score_adj;
755 * Before oom_score_adj of favourite (oom_score = 270) applications is
756 * independent of lru_state, now we consider lru_state, while
757 * killing favourite process.
760 if (oom_score_adj == OOMADJ_FAVORITE && pai->lru_state >= PROC_BACKGROUND)
761 ti.oom_score_lru = OOMADJ_FAVORITE + OOMADJ_FAVORITE_APP_INCREASE * pai->lru_state;
763 ti.oom_score_lru = oom_score_adj;
766 ti.pids = g_array_new(false, false, sizeof(pid_t));
767 g_array_append_val(ti.pids, ti.pid);
768 gslist_for_each_item(iterchild, pai->childs) {
769 pid_t child = GPOINTER_TO_PID(iterchild->data);
770 g_array_append_val(ti.pids, child);
775 g_array_append_val(candidates, ti);
778 proc_app_list_close();
780 if (!candidates->len) {
781 status = LOWMEM_RECLAIM_NEXT_TYPE;
785 _D("[LMK] candidate ratio=%d/%d", candidates->len, total_count);
788 for (i = 0; i < candidates->len; i++) {
789 struct task_info *tsk;
791 tsk = &g_array_index(candidates, struct task_info, i);
792 tsk->size = lowmem_get_task_mem_usage_rss(tsk);
796 * In case of start_oom == OOMADJ_SU,
797 * we're going to try to kill some of processes in /proc
798 * to handle low memory situation.
799 * It can find malicious system process even though it has low oom score.
801 if (start_oom == OOMADJ_SU)
802 lowmem_get_pids_proc(candidates);
804 g_array_sort(candidates, (GCompareFunc)compare_victims);
806 for (i = 0; i < candidates->len; i++) {
807 struct task_info *tsk;
809 if (i >= max_victims) {
810 status = LOWMEM_RECLAIM_NEXT_TYPE;
815 * Available memory is checking only every
816 * num_vict_between_check process for reducing burden.
818 if (!(i % num_vict_between_check)) {
819 if (proc_get_mem_available() > threshold) {
820 status = LOWMEM_RECLAIM_DONE;
825 if (!(flags & OOM_NOMEMORY_CHECK) &&
826 total_victim_size >= should_be_freed_kb) {
827 _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
828 victim, max_victims, total_victim_size);
829 status = LOWMEM_RECLAIM_DONE;
833 tsk = &g_array_index(candidates, struct task_info, i);
835 status = lowmem_check_kill_continued(tsk, flags);
836 if (status != LOWMEM_RECLAIM_CONT)
839 _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n", tsk->pid, tsk->oom_score_adj);
841 ret = lowmem_kill_victim(tsk, flags, i, &victim_size);
842 if (ret != RESOURCED_ERROR_NONE)
845 total_victim_size += victim_size;
849 lowmem_free_task_info_array(candidates);
850 *total_size = total_victim_size;
851 if(*completed != LOWMEM_RECLAIM_CONT)
854 *completed = LOWMEM_RECLAIM_NEXT_TYPE;
858 static int calculate_range_of_oom(enum cgroup_type type, int *min, int *max)
860 if (type == CGROUP_VIP || type >= CGROUP_END || type <= CGROUP_TOP) {
861 _E("cgroup type (%d) is out of scope", type);
862 return RESOURCED_ERROR_FAIL;
865 *max = cgroup_get_highest_oom_score_adj(type);
866 *min = cgroup_get_lowest_oom_score_adj(type);
868 return RESOURCED_ERROR_NONE;
871 static void lowmem_handle_request(struct lowmem_control *ctl)
873 int start_oom, end_oom;
874 int count = 0, victim_cnt = 0;
875 int max_victim_cnt = ctl->count;
876 int status = LOWMEM_RECLAIM_NONE;
877 unsigned int available = 0;
878 unsigned int total_size = 0;
879 unsigned int current_size = 0;
880 unsigned int reclaim_size, shortfall = 0;
881 enum cgroup_type cgroup_type = ctl->type;
883 available = proc_get_mem_available();
884 reclaim_size = ctl->size > available
885 ? ctl->size - available : 0;
888 status = LOWMEM_RECLAIM_DONE;
893 /* Prepare LMK to start doing it's job. Check preconditions. */
894 if (calculate_range_of_oom(cgroup_type, &start_oom, &end_oom))
897 lmk_start_threshold = get_root_memcg_info()->threshold[MEM_LEVEL_OOM];
898 shortfall = is_memory_recovered(&available, ctl->size);
900 if (!shortfall || !reclaim_size) {
901 status = LOWMEM_RECLAIM_DONE;
907 victim_cnt = lowmem_kill_victims(max_victim_cnt, start_oom, end_oom,
908 reclaim_size, ctl->flags, ¤t_size, &status, ctl->size);
911 current_size = KBYTE_TO_MBYTE(current_size);
912 reclaim_size -= reclaim_size > current_size
913 ? current_size : reclaim_size;
914 total_size += current_size;
916 _I("[LMK] current: kill %d victims, reclaim_size=%uMB from %d to %d status=%s",
917 victim_cnt, current_size,
918 start_oom, end_oom, convert_status_to_str(status));
921 if ((status == LOWMEM_RECLAIM_DONE) ||
922 (status == LOWMEM_RECLAIM_DROP) ||
923 (status == LOWMEM_RECLAIM_RETRY))
927 * If it doesn't finish reclaiming memory in first operation,
928 - if flags has OOM_IN_DEPTH,
929 try to find victims again in the active cgroup.
930 otherwise, just return because there is no more victims in the desired cgroup.
931 - if flags has OOM_REVISE,
932 it means that resourced can't find victims from proc_app_list.
933 So, it should search victims or malicious process from /proc.
934 But searching /proc leads to abnormal behaviour.
935 (Make sluggish or kill same victims continuously)
936 Thus, otherwise, just return in first operation and wait some period.
938 if (cgroup_type == CGROUP_LOW) {
939 cgroup_type = CGROUP_MEDIUM;
941 } else if ((cgroup_type == CGROUP_MEDIUM) && (ctl->flags & OOM_IN_DEPTH)) {
942 cgroup_type = CGROUP_HIGH;
943 if(ctl->flags & OOM_FORCE)
944 max_victim_cnt = FOREGROUND_VICTIMS;
946 } else if ((cgroup_type == CGROUP_HIGH) && (ctl->flags & OOM_IN_DEPTH)) {
947 status = LOWMEM_RECLAIM_RETRY;
948 ctl->type = CGROUP_ROOT;
950 else if (cgroup_type == CGROUP_ROOT) {
951 status = LOWMEM_RECLAIM_RETRY;
954 _I("[LMK] Done: killed %d processes reclaimed=%uMB remaining=%uMB shortfall=%uMB status=%s",
955 count, total_size, reclaim_size, shortfall, convert_status_to_str(status));
957 /* After we finish reclaiming it's worth to remove oldest memps logs */
958 ctl->status = status;
961 static void *lowmem_reclaim_worker(void *arg)
963 struct lowmem_worker *lmw = (struct lowmem_worker *)arg;
965 setpriority(PRIO_PROCESS, 0, OOM_KILLER_PRIORITY);
967 g_async_queue_ref(lmw->queue);
971 struct lowmem_control *ctl;
973 LOWMEM_WORKER_IDLE(lmw);
974 /* Wait on any wake-up call */
975 ctl = g_async_queue_pop(lmw->queue);
977 if (ctl->flags & OOM_DROP)
978 LOWMEM_DESTROY_REQUEST(ctl);
980 if (!LOWMEM_WORKER_IS_ACTIVE(lmw) || !ctl)
983 LOWMEM_WORKER_RUN(lmw);
985 _D("[LMK] %d tries", ++try_count);
986 lowmem_handle_request(ctl);
988 * Case the process failed to reclaim requested amount of memory
989 * or still under have memory pressure - try the timeout wait.
990 * There is a chance this will get woken-up in a better reality.
992 if (ctl->status == LOWMEM_RECLAIM_RETRY &&
993 !(ctl->flags & OOM_SINGLE_SHOT)) {
994 unsigned int available = proc_get_mem_available();
996 if (available >= ctl->size) {
997 _I("[LMK] Memory restored: requested=%uMB available=%uMB\n",
998 ctl->size, available);
999 ctl->status = LOWMEM_RECLAIM_DONE;
1002 LOWMEM_DESTROY_REQUEST(ctl);
1003 LOWMEM_WORKER_IDLE(lmw);
1007 if (LOWMEM_WORKER_IS_ACTIVE(lmw)) {
1008 g_usleep(LMW_RETRY_WAIT_TIMEOUT_MSEC);
1009 ctl->flags |= OOM_REVISE;
1015 * The ctl callback would check available size again.
1016 * And it is last point in reclaiming worker.
1017 * Resourced sent SIGKILL signal to victim processes
1018 * so it should wait for a some seconds until each processes returns memory.
1020 g_usleep(LMW_LOOP_WAIT_TIMEOUT_MSEC);
1024 /* The lmk becomes the owner of all queued requests .. */
1025 LOWMEM_DESTROY_REQUEST(ctl);
1026 LOWMEM_WORKER_IDLE(lmw);
1028 g_async_queue_unref(lmw->queue);
1032 static void change_lowmem_state(unsigned int mem_state)
1034 cur_mem_state = mem_state;
1035 lmk_start_threshold = get_root_memcg_info()->threshold[MEM_LEVEL_OOM];
1037 resourced_notify(RESOURCED_NOTIFIER_MEM_LEVEL_CHANGED,
1038 (void *)&cur_mem_state);
1041 /* only app can call this function
1042 * that is, service cannot call the function
1044 static void lowmem_swap_memory(char *path)
1046 unsigned int available;
1048 if (cur_mem_state == MEM_LEVEL_HIGH)
1051 if (swap_get_state() != SWAP_ON)
1054 available = proc_get_mem_available();
1055 if (cur_mem_state != MEM_LEVEL_LOW &&
1056 available <= get_root_memcg_info()->threshold[MEM_LEVEL_LOW])
1057 swap_activate_act();
1059 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
1060 memcg_swap_status = true;
1063 void lowmem_trigger_swap(pid_t pid, char *path, bool move)
1067 int lowest_oom_score_adj;
1070 _E("[SWAP] Unknown memory cgroup path to swap");
1074 /* In this case, corresponding process will be moved to memory CGROUP_LOW.
1077 error = proc_get_oom_score_adj(pid, &oom_score_adj);
1079 _E("[SWAP] Cannot get oom_score_adj of pid (%d)", pid);
1083 lowest_oom_score_adj = cgroup_get_lowest_oom_score_adj(CGROUP_LOW);
1085 if (oom_score_adj < lowest_oom_score_adj) {
1086 oom_score_adj = lowest_oom_score_adj;
1087 /* End of this funciton, 'lowmem_swap_memory()' funciton will be called */
1088 proc_set_oom_score_adj(pid, oom_score_adj, find_app_info(pid));
1093 /* Correponding process is already managed per app or service.
1094 * In addition, if some process is already located in the CGROUP_LOW, then just do swap
1096 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
1099 static void memory_level_send_system_event(int lv)
1105 case MEM_LEVEL_HIGH:
1106 case MEM_LEVEL_MEDIUM:
1108 str = EVT_VAL_MEMORY_NORMAL;
1110 case MEM_LEVEL_CRITICAL:
1111 str = EVT_VAL_MEMORY_SOFT_WARNING;
1114 str = EVT_VAL_MEMORY_HARD_WARNING;
1117 _E("Invalid state");
1121 b = bundle_create();
1123 _E("Failed to create bundle");
1127 bundle_add_str(b, EVT_KEY_LOW_MEMORY, str);
1128 eventsystem_send_system_event(SYS_EVENT_LOW_MEMORY, b);
1132 static void high_mem_act(void)
1136 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1138 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1139 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1140 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1141 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1142 memory_level_send_system_event(MEM_LEVEL_HIGH);
1145 change_lowmem_state(MEM_LEVEL_HIGH);
1147 if (swap_get_state() == SWAP_ON && memcg_swap_status) {
1148 resourced_notify(RESOURCED_NOTIFIER_SWAP_UNSET_LIMIT, get_memcg_info(CGROUP_LOW));
1149 memcg_swap_status = false;
1151 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1152 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1153 (void *)CGROUP_FREEZER_ENABLED);
1156 static void swap_activate_act(void)
1160 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1162 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1164 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1165 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1166 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1167 memory_level_send_system_event(MEM_LEVEL_LOW);
1169 change_lowmem_state(MEM_LEVEL_LOW);
1170 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1171 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1172 (void *)CGROUP_FREEZER_ENABLED);
1174 if (swap_get_state() != SWAP_ON)
1175 resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
1178 static void dedup_act(enum ksm_scan_mode mode)
1183 if (dedup_get_state() != DEDUP_ONE_SHOT)
1186 if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
1187 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1188 (void *)CGROUP_FREEZER_ENABLED);
1190 if (mode == KSM_SCAN_PARTIAL) {
1191 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1193 _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1195 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
1196 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1197 VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
1198 memory_level_send_system_event(MEM_LEVEL_MEDIUM);
1200 change_lowmem_state(MEM_LEVEL_MEDIUM);
1202 data = KSM_SCAN_PARTIAL;
1203 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
1204 } else if (mode == KSM_SCAN_FULL) {
1205 data = KSM_SCAN_FULL;
1206 resourced_notify(RESOURCED_NOTIFIER_DEDUP_SCAN, &data);
1210 static void swap_compact_act(void)
1212 change_lowmem_state(MEM_LEVEL_CRITICAL);
1213 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_CRITICAL);
1214 memory_level_send_system_event(MEM_LEVEL_CRITICAL);
1217 static void medium_cb(struct lowmem_control *ctl)
1219 if (ctl->status == LOWMEM_RECLAIM_DONE)
1221 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
1224 static void lmk_act(void)
1226 unsigned int available;
1228 int status = VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL;
1231 * Don't trigger reclaim worker
1232 * if it is already running
1234 if (LOWMEM_WORKER_IS_RUNNING(&lmw))
1237 ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
1239 _D("vconf_get_int fail %s", VCONFKEY_SYSMAN_LOW_MEMORY);
1241 memory_level_send_system_event(MEM_LEVEL_OOM);
1242 if (status != VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING) {
1243 if (proc_get_freezer_status() == CGROUP_FREEZER_ENABLED)
1244 resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
1245 (void *)CGROUP_FREEZER_PAUSED);
1246 vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
1247 VCONFKEY_SYSMAN_LOW_MEMORY_HARD_WARNING);
1249 available = proc_get_mem_available();
1251 change_lowmem_state(MEM_LEVEL_OOM);
1253 if (available < get_root_memcg_info()->threshold_leave) {
1254 struct lowmem_control *ctl;
1256 ctl = LOWMEM_NEW_REQUEST();
1258 LOWMEM_SET_REQUEST(ctl, OOM_IN_DEPTH,
1259 CGROUP_LOW, get_root_memcg_info()->threshold_leave,
1260 num_max_victims, medium_cb);
1261 lowmem_queue_request(&lmw, ctl);
1265 resourced_notify(RESOURCED_NOTIFIER_SWAP_COMPACT, (void *)SWAP_COMPACT_MEM_LEVEL_OOM);
1268 * Flush resourced memory such as other processes.
1269 * Resourced can use both many fast bins and sqlite3 cache memery.
1276 static void lowmem_trigger_memory_state_action(int mem_state)
1279 * Check if the state we want to set is different from current
1280 * But it should except this condition if mem_state is already medium.
1281 * Otherwise, recalim worker couldn't run any more.
1283 if (mem_state != MEM_LEVEL_OOM && cur_mem_state == mem_state)
1286 switch (mem_state) {
1287 case MEM_LEVEL_HIGH:
1290 case MEM_LEVEL_MEDIUM:
1291 dedup_act(KSM_SCAN_PARTIAL);
1294 swap_activate_act();
1296 case MEM_LEVEL_CRITICAL:
1297 dedup_act(KSM_SCAN_FULL);
1308 static void lowmem_dump_cgroup_procs(struct memcg_info *mi)
1313 GArray *pids_array = NULL;
1315 cgroup_get_pids(mi->name, &pids_array);
1317 for (i = 0; i < pids_array->len; i++) {
1318 pid = g_array_index(pids_array, pid_t, i);
1319 lowmem_mem_usage_uss(pid, &size);
1320 _I("pid = %d, size = %u KB", pid, size);
1322 g_array_free(pids_array, true);
1325 static void memory_cgroup_proactive_lmk_act(enum cgroup_type type, struct memcg_info *mi)
1327 struct lowmem_control *ctl;
1329 /* To Do: only start to kill fg victim when no pending fg victim */
1330 lowmem_dump_cgroup_procs(mi);
1332 ctl = LOWMEM_NEW_REQUEST();
1334 LOWMEM_SET_REQUEST(ctl, OOM_SINGLE_SHOT | OOM_IN_DEPTH, type,
1335 mi->oomleave, num_max_victims, NULL);
1336 lowmem_queue_request(&lmw, ctl);
1340 static unsigned int check_mem_state(unsigned int available)
1343 for (mem_state = MEM_LEVEL_MAX - 1; mem_state > MEM_LEVEL_HIGH; mem_state--) {
1344 if (mem_state != MEM_LEVEL_OOM && available <= get_root_memcg_info()->threshold[mem_state])
1346 else if (mem_state == MEM_LEVEL_OOM && available <= lmk_start_threshold)
1353 /* setup memcg parameters depending on total ram size. */
1354 static void setup_memcg_params(void)
1356 unsigned long long total_ramsize;
1359 total_ramsize = BYTE_TO_MBYTE(totalram);
1361 _D("Total: %llu MB", total_ramsize);
1362 if (total_ramsize <= MEM_SIZE_64) {
1363 /* set thresholds for ram size 64M */
1364 proactive_threshold = PROACTIVE_64_THRES;
1365 proactive_leave = PROACTIVE_64_LEAVE;
1366 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_64_THRES_DEDUP);
1367 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_64_THRES_SWAP);
1368 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_64_THRES_LOW);
1369 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_64_THRES_MEDIUM);
1370 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_64_THRES_LEAVE);
1371 num_max_victims = CGROUP_ROOT_64_NUM_VICTIMS;
1372 } else if (total_ramsize <= MEM_SIZE_256) {
1373 /* set thresholds for ram size 256M */
1374 proactive_threshold = PROACTIVE_256_THRES;
1375 proactive_leave = PROACTIVE_256_LEAVE;
1376 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_256_THRES_DEDUP);
1377 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_256_THRES_SWAP);
1378 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_256_THRES_LOW);
1379 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_256_THRES_MEDIUM);
1380 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_256_THRES_LEAVE);
1381 num_max_victims = CGROUP_ROOT_256_NUM_VICTIMS;
1382 } else if (total_ramsize <= MEM_SIZE_448) {
1383 /* set thresholds for ram size 448M */
1384 proactive_threshold = PROACTIVE_448_THRES;
1385 proactive_leave = PROACTIVE_448_LEAVE;
1386 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_448_THRES_DEDUP);
1387 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_448_THRES_SWAP);
1388 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_448_THRES_LOW);
1389 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_448_THRES_MEDIUM);
1390 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_448_THRES_LEAVE);
1391 num_max_victims = CGROUP_ROOT_448_NUM_VICTIMS;
1392 } else if (total_ramsize <= MEM_SIZE_512) {
1393 /* set thresholds for ram size 512M */
1394 proactive_threshold = PROACTIVE_512_THRES;
1395 proactive_leave = PROACTIVE_512_LEAVE;
1396 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_512_THRES_DEDUP);
1397 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_512_THRES_SWAP);
1398 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_512_THRES_LOW);
1399 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_512_THRES_MEDIUM);
1400 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_512_THRES_LEAVE);
1401 num_max_victims = CGROUP_ROOT_512_NUM_VICTIMS;
1402 } else if (total_ramsize <= MEM_SIZE_768) {
1403 /* set thresholds for ram size 512M */
1404 proactive_threshold = PROACTIVE_768_THRES;
1405 proactive_leave = PROACTIVE_768_LEAVE;
1406 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_768_THRES_DEDUP);
1407 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_768_THRES_SWAP);
1408 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_768_THRES_LOW);
1409 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_768_THRES_MEDIUM);
1410 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_768_THRES_LEAVE);
1411 num_max_victims = CGROUP_ROOT_768_NUM_VICTIMS;
1412 } else if (total_ramsize <= MEM_SIZE_1024) {
1413 /* set thresholds for ram size more than 1G */
1414 proactive_threshold = PROACTIVE_1024_THRES;
1415 proactive_leave = PROACTIVE_1024_LEAVE;
1416 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_1024_THRES_DEDUP);
1417 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_1024_THRES_SWAP);
1418 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_1024_THRES_LOW);
1419 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_1024_THRES_MEDIUM);
1420 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_1024_THRES_LEAVE);
1421 num_max_victims = CGROUP_ROOT_1024_NUM_VICTIMS;
1422 } else if (total_ramsize <= MEM_SIZE_2048) {
1423 proactive_threshold = PROACTIVE_2048_THRES;
1424 proactive_leave = PROACTIVE_2048_LEAVE;
1425 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_2048_THRES_DEDUP);
1426 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_2048_THRES_SWAP);
1427 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_2048_THRES_LOW);
1428 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_2048_THRES_MEDIUM);
1429 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_2048_THRES_LEAVE);
1430 num_max_victims = CGROUP_ROOT_2048_NUM_VICTIMS;
1432 proactive_threshold = PROACTIVE_3072_THRES;
1433 proactive_leave = PROACTIVE_3072_LEAVE;
1434 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_MEDIUM, CGROUP_ROOT_3072_THRES_DEDUP);
1435 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_LOW, CGROUP_ROOT_3072_THRES_SWAP);
1436 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_CRITICAL, CGROUP_ROOT_3072_THRES_LOW);
1437 memcg_set_threshold(CGROUP_ROOT, MEM_LEVEL_OOM, CGROUP_ROOT_3072_THRES_MEDIUM);
1438 memcg_set_leave_threshold(CGROUP_ROOT, CGROUP_ROOT_3072_THRES_LEAVE);
1439 num_max_victims = CGROUP_ROOT_3072_NUM_VICTIMS;
1443 static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
1445 int cur_oom_score_adj;
1447 struct memcg_info *mi;
1448 int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
1450 if(next_memcg_idx < CGROUP_VIP || next_memcg_idx > CGROUP_LOW) {
1451 _E("cgroup type (%d) should not be called", next_memcg_idx);
1454 mi = get_memcg_info(next_memcg_idx);
1461 cgroup_write_pid_fullpath(mi->name, pid);
1466 if (pai->main_pid == pid) {
1467 cur_oom_score_adj = pai->memory.oom_score_adj;
1468 cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
1470 /* -1 means that this pid is not yet registered at the memory cgroup
1471 * plz, reference proc_create_app_info function
1473 if (cur_oom_score_adj != OOMADJ_APP_MAX + 10) {
1474 /* VIP processes should not be asked to move. */
1475 if (cur_memcg_idx <= CGROUP_VIP) {
1476 _E("[DEBUG] current cgroup (%s) cannot be VIP or Root", convert_cgroup_type_to_str(cur_memcg_idx));
1481 _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));
1483 if (cur_oom_score_adj == next_oom_score_adj) {
1484 _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
1488 proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
1490 if (!lowmem_limit_move_cgroup(pai))
1493 if(cur_memcg_idx == next_memcg_idx)
1496 cgroup_write_pid_fullpath(mi->name, pid);
1497 if (next_memcg_idx == CGROUP_LOW)
1498 lowmem_swap_memory(get_memcg_info(CGROUP_LOW)->name);
1502 if (pai->memory.use_mem_limit)
1505 cgroup_write_pid_fullpath(mi->name, pid);
1509 static int lowmem_activate_worker(void)
1511 int ret = RESOURCED_ERROR_NONE;
1513 if (LOWMEM_WORKER_IS_ACTIVE(&lmw)) {
1517 lmw.queue = g_async_queue_new_full(lowmem_request_destroy);
1519 _E("Failed to create request queue\n");
1520 return RESOURCED_ERROR_FAIL;
1522 LOWMEM_WORKER_ACTIVATE(&lmw);
1523 ret = pthread_create(&lmw.worker_thread, NULL,
1524 (void *)lowmem_reclaim_worker, (void *)&lmw);
1526 LOWMEM_WORKER_DEACTIVATE(&lmw);
1527 _E("Failed to create LMK thread: %d\n", ret);
1529 pthread_detach(lmw.worker_thread);
1530 ret = RESOURCED_ERROR_NONE;
1535 static void lowmem_deactivate_worker(void)
1537 struct lowmem_control *ctl;
1539 if (!LOWMEM_WORKER_IS_ACTIVE(&lmw))
1542 LOWMEM_WORKER_DEACTIVATE(&lmw);
1543 lowmem_drain_queue(&lmw);
1545 ctl = LOWMEM_NEW_REQUEST();
1547 _E("Critical - g_slice alloc failed - Lowmem cannot be deactivated");
1550 ctl->flags = OOM_DROP;
1551 g_async_queue_push(lmw.queue, ctl);
1552 g_async_queue_unref(lmw.queue);
1555 static int lowmem_press_eventfd_read(int fd)
1557 uint64_t dummy_state;
1559 return read(fd, &dummy_state, sizeof(dummy_state));
1562 static void lowmem_press_root_cgroup_handler(void)
1564 static unsigned int prev_available;
1565 unsigned int available;
1568 available = proc_get_mem_available();
1569 if (prev_available == available)
1572 mem_state = check_mem_state(available);
1573 lowmem_trigger_memory_state_action(mem_state);
1575 prev_available = available;
1578 static void lowmem_press_cgroup_handler(enum cgroup_type type, struct memcg_info *mi)
1580 unsigned int usage, threshold;
1583 ret = memcg_get_anon_usage(mi->name, &usage);
1585 _D("getting anonymous memory usage fails");
1589 threshold = mi->threshold[MEM_LEVEL_OOM];
1590 if (usage >= threshold)
1591 memory_cgroup_proactive_lmk_act(type, mi);
1593 _I("anon page %u MB < medium threshold %u MB", BYTE_TO_MBYTE(usage),
1594 BYTE_TO_MBYTE(threshold));
1597 static bool lowmem_press_eventfd_handler(int fd, void *data)
1599 struct memcg_info *mi;
1600 enum cgroup_type type = CGROUP_ROOT;
1602 // FIXME: probably shouldn't get ignored
1603 if (lowmem_press_eventfd_read(fd) < 0)
1604 _E("Failed to read lowmem press event, %m\n");
1606 for (type = CGROUP_ROOT; type < CGROUP_END; type++) {
1607 if (!get_cgroup_tree(type) || !get_memcg_info(type))
1609 mi = get_memcg_info(type);
1610 if (fd == mi->evfd) {
1611 /* call low memory handler for this memcg */
1612 if (type == CGROUP_ROOT)
1613 lowmem_press_root_cgroup_handler();
1615 lowmem_press_cgroup_handler(type, mi);
1624 static int lowmem_press_register_eventfd(struct memcg_info *mi)
1627 const char *name = mi->name;
1628 static fd_handler_h handler;
1630 if (mi->threshold[MEM_LEVEL_OOM] == LOWMEM_THRES_INIT)
1633 evfd = memcg_set_eventfd(name, MEMCG_EVENTFD_MEMORY_PRESSURE,
1637 int saved_errno = errno;
1638 _E("fail to register event press fd %s cgroup", name);
1639 return -saved_errno;
1644 _I("register event fd success for %s cgroup", name);
1645 add_fd_read_handler(evfd, lowmem_press_eventfd_handler, NULL, NULL, &handler);
1649 static int lowmem_press_setup_eventfd(void)
1653 for (i = CGROUP_ROOT; i < CGROUP_END; i++) {
1654 if (!get_use_hierarchy(i))
1657 lowmem_press_register_eventfd(get_memcg_info(i));
1659 return RESOURCED_ERROR_NONE;
1662 static void lowmem_force_reclaim_cb(struct lowmem_control *ctl)
1664 lowmem_change_memory_state(MEM_LEVEL_HIGH, 0);
1667 int lowmem_trigger_reclaim(int flags, int victims, enum cgroup_type type, int threshold)
1669 struct lowmem_control *ctl = LOWMEM_NEW_REQUEST();
1674 flags |= OOM_FORCE | OOM_IN_DEPTH | OOM_SINGLE_SHOT;
1675 victims = victims > 0 ? victims : MAX_MEMORY_CGROUP_VICTIMS;
1676 type = type > 0 ? type : CGROUP_LOW;
1677 threshold = threshold > 0 ? threshold : get_root_memcg_info()->threshold_leave;
1679 lowmem_change_memory_state(MEM_LEVEL_CRITICAL, 1);
1680 LOWMEM_SET_REQUEST(ctl, flags,
1681 type, threshold, victims,
1682 lowmem_force_reclaim_cb);
1683 lowmem_queue_request(&lmw, ctl);
1688 void lowmem_trigger_swap_reclaim(enum cgroup_type type, int swap_size)
1692 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1693 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1695 size = get_root_memcg_info()->threshold_leave + BYTE_TO_MBYTE(swap_size);
1696 _I("reclaim from swap module, type : %d, size : %d, victims: %d", type, size, victims);
1697 lowmem_trigger_reclaim(0, victims, type, size);
1700 bool lowmem_fragmentated(void)
1702 struct buddyinfo bi;
1705 ret = proc_get_buddyinfo("Normal", &bi);
1710 * The fragmentation_size is the minimum count of order-2 pages in "Normal" zone.
1711 * If total buddy pages is smaller than fragmentation_size,
1712 * resourced will detect kernel memory is fragmented.
1713 * Default value is zero in low memory device.
1715 if (bi.page[PAGE_32K] + (bi.page[PAGE_64K] << 1) + (bi.page[PAGE_128K] << 2) +
1716 (bi.page[PAGE_256K] << 3) < fragmentation_size) {
1717 _I("fragmentation detected, need to execute proactive oom killer");
1723 static void lowmem_proactive_oom_killer(int flags, char *appid)
1725 unsigned int before;
1728 before = proc_get_mem_available();
1730 /* If memory state is medium or normal, just return and kill in oom killer */
1731 if (before < get_root_memcg_info()->threshold[MEM_LEVEL_OOM] || before > proactive_leave)
1734 victims = num_max_victims > MAX_PROACTIVE_HIGH_VICTIMS
1735 ? MAX_PROACTIVE_HIGH_VICTIMS : num_max_victims;
1737 #ifdef HEART_SUPPORT
1739 * This branch is used only when HEART module is compiled in and
1740 * it's MEMORY module must be enabled. Otherwise this is skipped.
1742 struct heart_memory_data *md = heart_memory_get_memdata(appid, DATA_LATEST);
1744 unsigned int rss, after, size;
1746 rss = KBYTE_TO_MBYTE(md->avg_rss);
1750 after = before - rss;
1752 * after launching app, ensure that available memory is
1753 * above threshold_leave
1755 if (after >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1758 if (proactive_threshold - rss >= get_root_memcg_info()->threshold[MEM_LEVEL_OOM])
1759 size = proactive_threshold;
1761 size = rss + get_root_memcg_info()->threshold[MEM_LEVEL_OOM] + THRESHOLD_MARGIN;
1763 _D("history based proactive LMK : avg rss %u, available %u required = %u MB",
1765 lowmem_trigger_reclaim(0, victims, CGROUP_LOW, size);
1772 * When there is no history data for the launching app,
1773 * it is necessary to check current fragmentation state or application manifest file.
1774 * So, resourced feels proactive LMK is required, run oom killer based on dynamic
1777 if (lowmem_fragmentated())
1781 * run proactive oom killer only when available is larger than
1782 * dynamic process threshold
1784 if (!proactive_threshold || before >= proactive_threshold)
1787 if (!(flags & PROC_LARGEMEMORY))
1792 * free THRESHOLD_MARGIN more than real should be freed,
1793 * because launching app is consuming up the memory.
1795 _D("Run threshold based proactive LMK: memory level to reach: %u\n",
1796 proactive_leave + THRESHOLD_MARGIN);
1797 lowmem_trigger_reclaim(0, victims, CGROUP_LOW, proactive_leave + THRESHOLD_MARGIN);
1800 unsigned int lowmem_get_proactive_thres(void)
1802 return proactive_threshold;
1805 static int lowmem_prelaunch_handler(void *data)
1807 struct proc_status *ps = (struct proc_status *)data;
1808 struct proc_app_info *pai = ps->pai;
1810 if (!pai || CHECK_BIT(pai->flags, PROC_SERVICEAPP))
1811 return RESOURCED_ERROR_NONE;
1813 lowmem_proactive_oom_killer(ps->pai->flags, ps->pai->appid);
1814 return RESOURCED_ERROR_NONE;
1817 int lowmem_control_handler(void *data)
1819 struct lowmem_control_data *lowmem_data;
1821 lowmem_data = (struct lowmem_control_data *)data;
1822 switch (lowmem_data->control_type) {
1823 case LOWMEM_MOVE_CGROUP:
1824 lowmem_move_memcgroup((pid_t)lowmem_data->pid,
1825 lowmem_data->oom_score_adj, lowmem_data->pai);
1830 return RESOURCED_ERROR_NONE;
1833 static int lowmem_bg_reclaim_handler(void *data)
1835 if (swap_get_state() != SWAP_ON)
1836 return RESOURCED_ERROR_NONE;
1839 return RESOURCED_ERROR_NONE;
1842 * Proactively reclaiming memory used by long-lived background processes
1843 * (such as widget instances) may be efficient on devices with limited
1844 * memory constraints. The pages used by such processes could be reclaimed
1845 * (if swap is enabled) earlier than they used to while minimizing the
1846 * impact on the user experience.
1848 resourced_notify(RESOURCED_NOTIFIER_SWAP_START, get_memcg_info(CGROUP_MEDIUM)->name);
1850 return RESOURCED_ERROR_NONE;
1853 static int calculate_threshold_size(double ratio)
1855 int size = (double)totalram * ratio / 100.0;
1859 static void load_configs(const char *path)
1861 struct memcg_conf *memcg_conf = get_memcg_conf();
1863 /* set MemoryGroupLimit section */
1864 for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
1865 if (memcg_conf->cgroup_limit[cgroup] > 0.0)
1866 memcg_info_set_limit(get_memcg_info(cgroup),
1867 memcg_conf->cgroup_limit[cgroup]/100.0, totalram);
1870 /* set MemoryLevelThreshold section */
1871 for (int lvl = MEM_LEVEL_MEDIUM; lvl < MEM_LEVEL_MAX; lvl++) {
1872 if (memcg_conf->threshold[lvl].percent &&
1873 memcg_conf->threshold[lvl].threshold > 0)
1874 memcg_set_threshold(CGROUP_ROOT, lvl,
1875 calculate_threshold_size(memcg_conf->threshold[lvl].threshold));
1876 else if (memcg_conf->threshold[lvl].threshold > 0)
1877 memcg_set_threshold(CGROUP_ROOT, lvl,
1878 memcg_conf->threshold[lvl].threshold);
1880 oom_popup_enable = memcg_conf->oom_popup;
1882 /* set MemoryAppTypeLimit and MemoryAppStatusLimit section */
1883 lowmem_memory_init(memcg_conf->service.memory, memcg_conf->widget.memory,
1884 memcg_conf->guiapp.memory, memcg_conf->background.memory);
1885 lowmem_action_init(memcg_conf->service.action, memcg_conf->widget.action,
1886 memcg_conf->guiapp.action, memcg_conf->background.action);
1891 static void print_mem_configs(void)
1893 /* print info of Memory section */
1894 for (int cgroup = CGROUP_VIP; cgroup < CGROUP_END; cgroup++) {
1895 _I("[DEBUG] set memory for cgroup '%s' to %u bytes",
1896 convert_cgroup_type_to_str(cgroup), get_memcg_info(cgroup)->limit);
1899 for (int mem_lvl = 0; mem_lvl < MEM_LEVEL_MAX; mem_lvl++)
1900 _I("[DEBUG] set threshold for memory level '%s' to %u MB",
1901 convert_memstate_to_str(mem_lvl), get_root_memcg_info()->threshold[mem_lvl]);
1903 _I("[DEBUG] set number of max victims as %d", num_max_victims);
1904 _I("[DEBUG] set threshold leave to %u MB", get_root_memcg_info()->threshold_leave);
1905 _I("[DEBUG] set proactive threshold to %u MB", proactive_threshold);
1906 _I("[DEBUG] set proactive low memory killer leave to %u MB", proactive_leave);
1908 /* print info of POPUP section */
1909 _I("[DEBUG] oom popup is %s", oom_popup_enable == true ? "enabled" : "disabled");
1911 /* print info of BackgroundReclaim section */
1912 _I("[DEBUG] Background reclaim is %s", bg_reclaim == true ? "enabled" : "disabled");
1915 #include "file-helper.h"
1917 /* To Do: should we need lowmem_fd_start, lowmem_fd_stop ?? */
1918 static int lowmem_init(void)
1920 int ret = RESOURCED_ERROR_NONE;
1922 _D("[DEBUG] resourced memory init start");
1925 ret = cgroup_make_full_subdir(MEMCG_PATH);
1926 ret_value_msg_if(ret < 0, ret, "memory cgroup init failed\n");
1927 memcg_params_init();
1929 setup_memcg_params();
1931 /* default configuration */
1932 load_configs(MEM_CONF_FILE);
1934 /* this function should be called after parsing configurations */
1935 memcg_write_limiter_params();
1936 print_mem_configs();
1938 /* make a worker thread called low memory killer */
1939 ret = lowmem_activate_worker();
1941 _E("[DEBUG] oom thread create failed\n");
1945 /* register threshold and event fd */
1946 ret = lowmem_press_setup_eventfd();
1948 _E("[DEBUG] eventfd setup failed");
1953 lowmem_limit_init();
1954 lowmem_system_init();
1956 register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1957 register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1958 register_notifier(RESOURCED_NOTIFIER_LCD_OFF, lowmem_bg_reclaim_handler);
1963 static int lowmem_exit(void)
1965 if (strncmp(event_level, MEMCG_DEFAULT_EVENT_LEVEL, sizeof(MEMCG_DEFAULT_EVENT_LEVEL)))
1968 lowmem_deactivate_worker();
1969 lowmem_limit_exit();
1970 lowmem_system_exit();
1972 unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
1973 unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
1974 unregister_notifier(RESOURCED_NOTIFIER_LCD_OFF, lowmem_bg_reclaim_handler);
1976 return RESOURCED_ERROR_NONE;
1979 static int resourced_memory_init(void *data)
1981 lowmem_ops = &memory_modules_ops;
1982 return lowmem_init();
1985 static int resourced_memory_finalize(void *data)
1987 return lowmem_exit();
1990 void lowmem_change_memory_state(int state, int force)
1997 unsigned int available = proc_get_mem_available();
1998 mem_state = check_mem_state(available);
2001 lowmem_trigger_memory_state_action(mem_state);
2004 unsigned long lowmem_get_ktotalram(void)
2009 unsigned long lowmem_get_totalram(void)
2014 void lowmem_restore_memcg(struct proc_app_info *pai)
2018 struct cgroup *cgroup = NULL;
2019 struct memcg_info *mi = NULL;
2020 pid_t pid = pai->main_pid;
2022 ret = cgroup_pid_get_path("memory", pid, &cgpath);
2026 for (index = CGROUP_END-1; index >= CGROUP_ROOT; index--) {
2027 cgroup = get_cgroup_tree(index);
2031 mi = cgroup->memcg_info;
2035 if (!strcmp(cgroup->hashname, ""))
2037 if (strstr(cgpath, cgroup->hashname))
2040 pai->memory.memcg_idx = index;
2041 pai->memory.memcg_info = mi;
2042 if(strstr(cgpath, pai->appid))
2043 pai->memory.use_mem_limit = true;
2048 static struct module_ops memory_modules_ops = {
2049 .priority = MODULE_PRIORITY_HIGH,
2051 .init = resourced_memory_init,
2052 .exit = resourced_memory_finalize,
2055 MODULE_REGISTER(&memory_modules_ops)