--- /dev/null
+/**
+ * resourced
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either excontroller or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file lowmem-controller.c
+ * @desc Provides controller functionalities to kill procs/apps
+ */
+
+#include <string.h>
+#include <limits.h>
+
+#include "lowmem.h"
+#include "lowmem-controller.h"
+#include "proc-common.h"
+#include "proc-main.h"
+#include "resourced.h"
+#include "procfs.h"
+#include "trace.h"
+#include "util.h"
+#include "safe-kill.h"
+
+#define MAX_VICTIMS_BETWEEN_CHECK 3
+
+static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
+
+static int lowmem_kill_victim(const struct task_info *tsk, int flags,
+ int memps_log, unsigned int *victim_size,
+ void(*oom_popup)(void))
+{
+ pid_t pid;
+ int ret;
+ char appname[PATH_MAX];
+ int sigterm = 0;
+ struct proc_app_info *pai;
+
+ pid = tsk->pid;
+
+ if (pid <= 0 || pid == getpid())
+ return RESOURCED_ERROR_FAIL;
+
+ ret = proc_get_cmdline(pid, appname, sizeof appname);
+ if (ret == RESOURCED_ERROR_FAIL)
+ return RESOURCED_ERROR_FAIL;
+
+ if (!strcmp("memps", appname) ||
+ !strcmp("crash-worker", appname) ||
+ !strcmp("system-syspopup", appname)) {
+ _E("%s(%d) was selected, skip it", appname, pid);
+ return RESOURCED_ERROR_FAIL;
+ }
+
+ pai = tsk->pai;
+ if (pai) {
+ resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
+ pid, NULL, NULL, PROC_TYPE_NONE);
+
+ if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
+ sigterm = 1;
+ } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED &&
+ tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
+ int app_flag = pai->flags;
+ sigterm = app_flag & PROC_SIGTERM;
+ }
+
+ if (pai->memory.oom_killed)
+ sigterm = 0;
+
+ pai->memory.oom_killed = true;
+ }
+
+ if (sigterm)
+ safe_kill(pid, SIGTERM);
+ else
+ safe_kill(pid, SIGKILL);
+
+ _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u KB, sigterm = %d\n",
+ flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
+ tsk->size, sigterm);
+ *victim_size = tsk->size;
+
+ if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
+ return RESOURCED_ERROR_NONE;
+
+ oom_popup();
+
+ return RESOURCED_ERROR_NONE;
+}
+
+/* return LOWMEM_RECLAIM_CONT when killing should be continued */
+static int lowmem_check_kill_continued(struct task_info *tsk, int flags,
+ unsigned lmk_start_threshold_mb)
+{
+ unsigned int available_mb = 0;
+
+ /**
+ * Processes with the priority higher than perceptible are killed
+ * only when the available memory is less than dynamic oom threshold.
+ */
+ if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
+ return LOWMEM_RECLAIM_CONT;
+
+ if (flags & (OOM_FORCE | OOM_SINGLE_SHOT)) {
+ _I("[LMK] %d is dropped during force kill, flag=%d",
+ tsk->pid, flags);
+ return LOWMEM_RECLAIM_DROP;
+ }
+ available_mb = proc_get_mem_available();
+ if (available_mb > lmk_start_threshold_mb) {
+ _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
+ available_mb, lmk_start_threshold_mb);
+ return LOWMEM_RECLAIM_RETRY;
+ }
+ return LOWMEM_RECLAIM_CONT;
+}
+
+int lowmem_controller_kill_candidates(GArray *candidates,
+ unsigned should_be_freed, unsigned int threshold,
+ int max_victims, int flags,
+ int *status, unsigned int *total_victim_size,
+ unsigned lmk_start_threshold_mb,
+ void(*oom_popup)(void))
+{
+ int ret_kill = 0;
+ int victim_cnt = 0;
+ unsigned int victim_size = 0;
+ unsigned int victim_size_sum = 0;
+ int killer_status = *status;
+ int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
+
+ for (int i = 0; i < candidates->len; i++) {
+ struct task_info *tsk;
+
+ if (i >= max_victims) {
+ killer_status = LOWMEM_RECLAIM_NEXT_TYPE;
+ break;
+ }
+
+ /**
+ * Available memory is checking only every
+ * num_vict_between_check process for reducing burden.
+ */
+ if (!(i % num_vict_between_check) &&
+ proc_get_mem_available() > threshold) {
+ killer_status = LOWMEM_RECLAIM_DONE;
+ break;
+ }
+
+ if (!(flags & OOM_NOMEMORY_CHECK) &&
+ victim_size_sum >= should_be_freed_kb) {
+ _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
+ victim_cnt, max_victims, victim_size_sum);
+ killer_status = LOWMEM_RECLAIM_DONE;
+ break;
+ }
+
+ tsk = &g_array_index(candidates, struct task_info, i);
+
+ killer_status = lowmem_check_kill_continued(tsk, flags,
+ lmk_start_threshold_mb);
+ if (killer_status != LOWMEM_RECLAIM_CONT)
+ break;
+
+ _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n",
+ tsk->pid, tsk->oom_score_adj);
+
+ ret_kill = lowmem_kill_victim(tsk, flags, i, &victim_size,
+ oom_popup);
+ if (ret_kill != RESOURCED_ERROR_NONE)
+ continue;
+ victim_cnt++;
+ victim_size_sum += victim_size;
+ }
+
+ *status = killer_status;
+ *total_victim_size = victim_size_sum;
+
+ return victim_cnt;
+}
--- /dev/null
+/**
+ * resourced
+ *
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either excontroller or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @file lowmem-controller.h
+ * @desc Functions for controller features.
+ */
+
+#ifndef __LOWMEM_CONTROLLER_H__
+#define __LOWMEM_CONTROLLER_H__
+
+int lowmem_controller_kill_candidates(GArray *candidates,
+ unsigned should_be_freed, unsigned int threshold,
+ int max_victims, int flags,
+ int *status, unsigned int *total_victim_size,
+ unsigned lmk_start_threshold_mb,
+ void(*oom_popup)(void));
+
+#endif /* __LOWMEM_CONTROLLER_H__ */
#include "lowmem-system.h"
#include "lowmem-limit.h"
#include "lowmem-governor.h"
+#include "lowmem-controller.h"
#include "proc-common.h"
#include "procfs.h"
#include "freezer.h"
#include "util.h"
#include "fd-handler.h"
#include "resourced-helper-worker.h"
-#include "safe-kill.h"
#include "dedup-common.h"
-#define MAX_VICTIMS_BETWEEN_CHECK 3
#define MAX_PROACTIVE_HIGH_VICTIMS 4
#define FOREGROUND_VICTIMS 1
#define OOM_KILLER_PRIORITY -20
static size_t cur_mem_state = MEM_LEVEL_HIGH;
static int num_max_victims = MAX_MEMORY_CGROUP_VICTIMS;
-static int num_vict_between_check = MAX_VICTIMS_BETWEEN_CHECK;
static unsigned long long totalram_bytes;
static unsigned long totalram_kb;
return total_size_kb;
}
-static int lowmem_kill_victim(const struct task_info *tsk,
- int flags, int memps_log, unsigned int *victim_size)
-{
- pid_t pid;
- int ret;
- char appname[PATH_MAX];
- int sigterm = 0;
- struct proc_app_info *pai;
-
- pid = tsk->pid;
-
- if (pid <= 0 || pid == getpid())
- return RESOURCED_ERROR_FAIL;
-
- ret = proc_get_cmdline(pid, appname, sizeof appname);
- if (ret == RESOURCED_ERROR_FAIL)
- return RESOURCED_ERROR_FAIL;
-
- if (!strcmp("memps", appname) ||
- !strcmp("crash-worker", appname) ||
- !strcmp("system-syspopup", appname)) {
- _E("%s(%d) was selected, skip it", appname, pid);
- return RESOURCED_ERROR_FAIL;
- }
-
- pai = tsk->pai;
- if (pai) {
- resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
- pid, NULL, NULL, PROC_TYPE_NONE);
-
- if (tsk->oom_score_lru <= OOMADJ_BACKGRD_LOCKED) {
- sigterm = 1;
- } else if (tsk->oom_score_lru > OOMADJ_BACKGRD_LOCKED && tsk->oom_score_lru < OOMADJ_BACKGRD_UNLOCKED) {
- int app_flag = pai->flags;
- sigterm = app_flag & PROC_SIGTERM;
- }
-
- if (pai->memory.oom_killed)
- sigterm = 0;
-
- pai->memory.oom_killed = true;
- }
-
- if (sigterm)
- safe_kill(pid, SIGTERM);
- else
- safe_kill(pid, SIGKILL);
-
- _D("[LMK] we killed, force(%d), %d (%s) score = %d, size: rss = %u KB, sigterm = %d\n",
- flags & OOM_FORCE, pid, appname, tsk->oom_score_adj,
- tsk->size, sigterm);
- *victim_size = tsk->size;
-
- if (tsk->oom_score_lru > OOMADJ_FOREGRD_UNLOCKED)
- return RESOURCED_ERROR_NONE;
-
- if (oom_popup_enable && !oom_popup) {
- lowmem_launch_oompopup();
- oom_popup = true;
- }
-
- return RESOURCED_ERROR_NONE;
-}
-
-/* return LOWMEM_RECLAIM_CONT when killing should be continued */
-static int lowmem_check_kill_continued(struct task_info *tsk, int flags)
-{
- unsigned int available_mb;
-
- /*
- * Processes with the priority higher than perceptible are killed
- * only when the available memory is less than dynamic oom threshold.
- */
- if (tsk->oom_score_lru > OOMADJ_BACKGRD_PERCEPTIBLE)
- return LOWMEM_RECLAIM_CONT;
-
- if (flags & (OOM_FORCE|OOM_SINGLE_SHOT)) {
- _I("[LMK] %d is dropped during force kill, flag=%d",
- tsk->pid, flags);
- return LOWMEM_RECLAIM_DROP;
- }
- available_mb = proc_get_mem_available();
- if (available_mb > lmk_start_threshold_mb) {
- _I("[LMK] available=%d MB, larger than %u MB, do not kill foreground",
- available_mb, lmk_start_threshold_mb);
- return LOWMEM_RECLAIM_RETRY;
- }
- return LOWMEM_RECLAIM_CONT;
-}
-
static void lowmem_free_task_info_array(GArray *array)
{
int i;
return should_be_freed_mb;
}
+static void lowmem_oom_popup_once(void)
+{
+ if (oom_popup_enable && !oom_popup) {
+ lowmem_launch_oompopup();
+ oom_popup = true;
+ }
+}
+
/**
* @brief Terminate up to max_victims processes after finding them from pai.
It depends on proc_app_info lists
unsigned int *total_size, int *completed, unsigned int threshold)
{
GSList *proc_app_list = NULL;
- int i, ret, victim = 0;
- unsigned int victim_size = 0;
unsigned int total_victim_size = 0;
+ int victim_cnt = 0;
int status = LOWMEM_RECLAIM_NONE;
GArray *candidates = NULL;
- int should_be_freed_kb = MBYTE_TO_KBYTE(should_be_freed);
proc_app_list = proc_app_list_open();
goto leave;
}
- for (i = 0; i < candidates->len; i++) {
- struct task_info *tsk;
-
- if (i >= max_victims) {
- status = LOWMEM_RECLAIM_NEXT_TYPE;
- break;
- }
-
- /*
- * Available memory is checking only every
- * num_vict_between_check process for reducing burden.
- */
- if (!(i % num_vict_between_check)) {
- if (proc_get_mem_available() > threshold) {
- status = LOWMEM_RECLAIM_DONE;
- break;
- }
- }
-
- if (!(flags & OOM_NOMEMORY_CHECK) &&
- total_victim_size >= should_be_freed_kb) {
- _D("[LMK] victim=%d, max_victims=%d, total_size=%uKB",
- victim, max_victims, total_victim_size);
- status = LOWMEM_RECLAIM_DONE;
- break;
- }
-
- tsk = &g_array_index(candidates, struct task_info, i);
-
- status = lowmem_check_kill_continued(tsk, flags);
- if (status != LOWMEM_RECLAIM_CONT)
- break;
-
- _I("[LMK] select victims from proc_app_list pid(%d) with oom_score_adj(%d)\n", tsk->pid, tsk->oom_score_adj);
-
- ret = lowmem_kill_victim(tsk, flags, i, &victim_size);
- if (ret != RESOURCED_ERROR_NONE)
- continue;
- victim++;
- total_victim_size += victim_size;
- }
+ victim_cnt = lowmem_controller_kill_candidates(candidates,
+ should_be_freed, threshold,
+ max_victims, flags,
+ &status, &total_victim_size,
+ lmk_start_threshold_mb,
+ lowmem_oom_popup_once);
leave:
lowmem_free_task_info_array(candidates);
*completed = status;
else
*completed = LOWMEM_RECLAIM_NEXT_TYPE;
- return victim;
+ return victim_cnt;
}
static int calculate_range_of_oom(enum oom_score score, int *min, int *max)