4 * Copyright (c) 2023 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 excontroller or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 * @file lowmem-controller.c
21 * @desc Provides controller functionalities to kill procs/apps
28 #include "lowmem-controller.h"
29 #include "proc-common.h"
30 #include "proc-main.h"
31 #include "resourced.h"
35 #include "safe-kill.h"
37 #define MAX_VICTIMS_BETWEEN_CHECK 3
39 static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
41 static int lowmem_kill_victim(const struct task_info *tsk, int flags,
42 int memps_log, unsigned int *victim_size,
43 void(*oom_popup)(void))
47 char appname[PATH_MAX];
49 struct proc_app_info *pai;
53 if (pid <= 0 || pid == getpid())
54 return RESOURCED_ERROR_FAIL;
56 ret = proc_get_cmdline(pid, appname, sizeof appname);
57 if (ret == RESOURCED_ERROR_FAIL)
58 return RESOURCED_ERROR_FAIL;
60 if (!strcmp("memps", appname) ||
61 !strcmp("crash-worker", appname) ||
62 !strcmp("system-syspopup", appname)) {
63 _E("%s(%d) was selected, skip it", appname, pid);
64 return RESOURCED_ERROR_FAIL;
69 resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
70 pid, NULL, NULL, PROC_TYPE_NONE);
72 if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
74 } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED &&
75 tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
76 int app_flag = pai->flags;
77 sigterm = app_flag & PROC_SIGTERM;
80 if (pai->memory.oom_killed)
83 pai->memory.oom_killed = true;
87 safe_kill(pid, SIGTERM);
89 safe_kill(pid, SIGKILL);
91 _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u KB, sigterm = %d\n",
92 flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
94 *victim_size = tsk->size;
96 if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
97 return RESOURCED_ERROR_NONE;
101 return RESOURCED_ERROR_NONE;
104 /* return LOWMEM_RECLAIM_CONT when killing should be continued */
105 static int lowmem_check_kill_continued(struct task_info *tsk, int flags,
106 unsigned lmk_start_threshold_mb)
108 unsigned int available_mb = 0;
111 * Processes with the priority higher than perceptible are killed
112 * only when the available memory is less than dynamic oom threshold.
114 if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
115 return LOWMEM_RECLAIM_CONT;
117 if (flags & (OOM_FORCE | OOM_SINGLE_SHOT)) {
118 _I("[LMK] %d is dropped during force kill, flag=%d",
120 return LOWMEM_RECLAIM_DROP;
122 available_mb = proc_get_mem_available();
123 if (available_mb > lmk_start_threshold_mb) {
124 _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
125 available_mb, lmk_start_threshold_mb);
126 return LOWMEM_RECLAIM_RETRY;
128 return LOWMEM_RECLAIM_CONT;
131 int lowmem_controller_kill_candidates(GArray *candidates,
132 unsigned should_be_freed, unsigned int threshold,
133 int max_victims, int flags,
134 int *status, unsigned int *total_victim_size,
135 unsigned lmk_start_threshold_mb,
136 void(*oom_popup)(void))
140 unsigned int victim_size = 0;
141 unsigned int victim_size_sum = 0;
142 int killer_status = *status;
143 int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
145 for (int i = 0; i < candidates->len; i++) {
146 struct task_info *tsk;
148 if (i >= max_victims) {
149 killer_status = LOWMEM_RECLAIM_NEXT_TYPE;
154 * Available memory is checking only every
155 * num_vict_between_check process for reducing burden.
157 if (!(i % num_vict_between_check) &&
158 proc_get_mem_available() > threshold) {
159 killer_status = LOWMEM_RECLAIM_DONE;
163 if (!(flags & OOM_NOMEMORY_CHECK) &&
164 victim_size_sum >= should_be_freed_kb) {
165 _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
166 victim_cnt, max_victims, victim_size_sum);
167 killer_status = LOWMEM_RECLAIM_DONE;
171 tsk = &g_array_index(candidates, struct task_info, i);
173 killer_status = lowmem_check_kill_continued(tsk, flags,
174 lmk_start_threshold_mb);
175 if (killer_status != LOWMEM_RECLAIM_CONT)
178 _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n",
179 tsk->pid, tsk->oom_score_adj);
181 ret_kill = lowmem_kill_victim(tsk, flags, i, &victim_size,
183 if (ret_kill != RESOURCED_ERROR_NONE)
186 victim_size_sum += victim_size;
189 *status = killer_status;
190 *total_victim_size = victim_size_sum;