4 * Copyright (c) 2000 - 2013 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.
27 #include <sys/types.h>
30 #include "resourced.h"
32 #include "proc-main.h"
34 #include "proc-process.h"
35 #include "lowmem-common.h"
36 #include "logging-common.h"
38 #include "swap-common.h"
39 #include "proc-noti.h"
42 #define PROC_OOM_SCORE_ADJ_PATH "/proc/%d/oom_score_adj"
43 #define PROC_SWEEP_TIMER 3
44 static GHashTable *proc_sweep_list;
45 static Ecore_Timer *proc_sweep_timer = NULL;
47 enum proc_background_type {
48 PROC_BACKGROUND_INACTIVE,
49 PROC_BACKGROUND_ACTIVE,
52 static int proc_backgrd_manage(int currentpid, int active)
54 int pid = -1, pgid, ret;
55 struct proc_status proc_data;;
57 struct dirent *dentry;
59 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
60 char appname[PROC_NAME_MAX];
62 int candidatepid[16] = {0,};
63 int cur_oom = -1, prev_oom=OOMADJ_BACKGRD_UNLOCKED, select_pid=0;
64 static int checkprevpid = 0;
65 unsigned long swap_args[2] = {0,};
66 unsigned long logging_args[3] = {0,};
68 ret = proc_get_cmdline(currentpid, appname);
69 if (ret == RESOURCED_ERROR_NONE) {
70 ret = resourced_proc_excluded(appname);
71 if (!active && !ret) {
72 proc_data.pid = currentpid;
73 proc_data.appid = appname;
74 resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD, &proc_data);
77 _D("BACKGRD MANAGE : don't manage background application by %d", currentpid);
78 return RESOURCED_ERROR_NONE;
82 dp = opendir("/proc");
84 _E("BACKGRD MANAGE : fail to open /proc");
85 return RESOURCED_ERROR_FAIL;
87 while ((dentry = readdir(dp)) != NULL) {
89 if (!isdigit(dentry->d_name[0]))
92 pid = atoi(dentry->d_name);
97 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
98 fp = fopen(buf, "r+");
101 if (fgets(buf, sizeof(buf), fp) == NULL) {
107 logging_args[0] = (unsigned long)pid;
108 logging_args[1] = (unsigned long)pgid;
109 logging_args[2] = (unsigned long)cur_oom;
110 logging_control(LOGGING_INSERT_PROC_LIST, logging_args);
112 if (currentpid != pid && currentpid == pgid) {
113 proc_set_group(currentpid, pid);
118 if (active || checkprevpid == currentpid) {
123 if (select_pid != pid && select_pid == pgid && count < 16)
125 _D("found candidate child pid = %d, pgid = %d", pid, pgid);
126 candidatepid[count++] = pid;
131 swap_args[0] = (unsigned long)pid;
132 if (cur_oom > OOMADJ_BACKGRD_UNLOCKED && cur_oom > prev_oom
133 && !swap_status(SWAP_CHECK_PID, swap_args)) {
135 candidatepid[count++] = pid;
140 if (cur_oom >= OOMADJ_APP_MAX) {
143 } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
144 _D("BACKGRD : process %d set score %d (before %d)",
145 pid, cur_oom+OOMADJ_APP_INCREASE, cur_oom);
146 fprintf(fp, "%d", cur_oom+OOMADJ_APP_INCREASE);
152 _D("found candidate pid = %d, count = %d", candidatepid, count);
153 swap_args[0] = (unsigned long)candidatepid;
154 swap_args[1] = (unsigned long)count;
155 resourced_notify(RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID, swap_args);
157 checkprevpid = currentpid;
160 logging_control(LOGGING_UPDATE_PROC_INFO, NULL);
162 return RESOURCED_ERROR_NONE;
165 static int proc_foregrd_manage(int pid, int oom_score_adj)
169 struct proc_process_info_t *process_info =
170 find_process_info(NULL, pid, NULL);
173 ret = proc_set_oom_score_adj(pid, oom_score_adj);
177 gslist_for_each_item(iter, process_info->pids) {
178 struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
179 ret = proc_set_oom_score_adj(pid_info->pid, oom_score_adj);
184 void proc_kill_victiom(gpointer key, gpointer value, gpointer user_data)
186 int pid = *(gint*)key;
188 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
191 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
192 fp = fopen(buf, "r+");
194 _D("sweep proc_kill_victim : background process %d already terminated", pid);
197 if (fgets(buf, sizeof(buf), fp) == NULL) {
202 if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
204 _D("sweep memory : background process %d killed by sigkill", pid);
209 static Eina_Bool proc_check_sweep_cb(void *data)
211 GHashTable *List = (GHashTable *)data;
212 g_hash_table_foreach(List, proc_kill_victiom, NULL);
213 g_hash_table_destroy(List);
214 proc_sweep_list = NULL;
215 return ECORE_CALLBACK_CANCEL;
218 int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
223 struct dirent *dentry;
226 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
227 char appname[PROC_NAME_MAX];
230 int select_sweep_limit;
231 dp = opendir("/proc");
233 _E("BACKGRD MANAGE : fail to open /proc");
234 return RESOURCED_ERROR_FAIL;
236 if (proc_sweep_timer)
237 ecore_timer_del(proc_sweep_timer);
239 g_hash_table_destroy(proc_sweep_list);
240 proc_sweep_list = g_hash_table_new(g_int_hash, g_int_equal);
242 if (type == PROC_SWEEP_EXCLUDE_ACTIVE)
243 select_sweep_limit = OOMADJ_BACKGRD_UNLOCKED;
245 select_sweep_limit = OOMADJ_BACKGRD_LOCKED;
247 while ((dentry = readdir(dp)) != NULL) {
248 if (!isdigit(dentry->d_name[0]))
251 pid = atoi(dentry->d_name);
255 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
256 fp = fopen(buf, "r+");
259 if (fgets(buf, sizeof(buf), fp) == NULL) {
264 if (cur_oom >= select_sweep_limit) {
265 ret = proc_get_cmdline(pid, appname);
270 proc_remove_process_list(pid);
271 piddata = g_new(gint, 1);
273 g_hash_table_insert(proc_sweep_list, piddata, NULL);
275 _D("sweep memory : background process %d(%s) killed",
283 ecore_timer_add(PROC_SWEEP_TIMER, proc_check_sweep_cb, (void *)proc_sweep_list);
290 int proc_get_cmdline(pid_t pid, char *cmdline)
292 char buf[PROC_BUF_MAX];
293 char cmdline_buf[PROC_NAME_MAX];
297 sprintf(buf, "/proc/%d/cmdline", pid);
298 fp = fopen(buf, "r");
300 return RESOURCED_ERROR_FAIL;
302 if (fgets(cmdline_buf, PROC_NAME_MAX-1, fp) == NULL) {
304 return RESOURCED_ERROR_FAIL;
308 filename = strrchr(cmdline_buf, '/');
309 if (filename == NULL)
310 filename = cmdline_buf;
312 filename = filename + 1;
314 strncpy(cmdline, filename, PROC_NAME_MAX-1);
316 return RESOURCED_ERROR_NONE;
319 int proc_get_oom_score_adj(int pid, int *oom_score_adj)
321 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
325 return RESOURCED_ERROR_FAIL;
327 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
328 fp = fopen(buf, "r");
331 _E("fopen %s failed", buf);
332 return RESOURCED_ERROR_FAIL;
334 if (fgets(buf, sizeof(buf), fp) == NULL) {
336 return RESOURCED_ERROR_FAIL;
338 (*oom_score_adj) = atoi(buf);
340 return RESOURCED_ERROR_NONE;
343 int proc_set_oom_score_adj(int pid, int oom_score_adj)
345 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
347 unsigned long lowmem_args[2] = {0, };
349 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
350 fp = fopen(buf, "r+");
352 return RESOURCED_ERROR_FAIL;
353 if (fgets(buf, sizeof(buf), fp) == NULL) {
355 return RESOURCED_ERROR_FAIL;
357 fprintf(fp, "%d", oom_score_adj);
360 if (oom_score_adj >= OOMADJ_SU) {
361 lowmem_args[0] = (unsigned long)pid;
362 lowmem_args[1] = (unsigned long)oom_score_adj;
363 lowmem_control(LOWMEM_MOVE_CGROUP, lowmem_args);
368 int proc_set_foregrd(pid_t pid, int oom_score_adj)
372 switch (oom_score_adj) {
373 case OOMADJ_FOREGRD_LOCKED:
374 case OOMADJ_FOREGRD_UNLOCKED:
378 case OOMADJ_BACKGRD_LOCKED:
379 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_LOCKED);
381 case OOMADJ_BACKGRD_UNLOCKED:
383 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED);
386 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
387 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
397 int proc_set_backgrd(int pid, int oom_score_adj)
401 switch (oom_score_adj) {
402 case OOMADJ_BACKGRD_LOCKED:
403 case OOMADJ_BACKGRD_UNLOCKED:
407 case OOMADJ_FOREGRD_LOCKED:
408 proc_backgrd_manage(pid, PROC_BACKGROUND_ACTIVE);
409 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
411 case OOMADJ_FOREGRD_UNLOCKED:
412 proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE);
413 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
416 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
419 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
429 int proc_set_active(int pid, int oom_score_adj)
433 switch (oom_score_adj) {
434 case OOMADJ_FOREGRD_LOCKED:
435 case OOMADJ_BACKGRD_LOCKED:
438 /* don't change oom value pid */
441 case OOMADJ_FOREGRD_UNLOCKED:
442 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
444 case OOMADJ_BACKGRD_UNLOCKED:
445 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
447 case OOMADJ_SERVICE_DEFAULT:
448 case OOMADJ_SERVICE_BACKGRD:
449 ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_FOREGRD);
452 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED)
453 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
461 int proc_set_inactive(int pid, int oom_score_adj)
464 struct proc_process_info_t * processinfo;
465 switch (oom_score_adj) {
466 case OOMADJ_FOREGRD_UNLOCKED:
467 case OOMADJ_BACKGRD_UNLOCKED:
470 /* don't change oom value pid */
473 case OOMADJ_FOREGRD_LOCKED:
474 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
476 case OOMADJ_BACKGRD_LOCKED:
477 processinfo = find_process_info(NULL, pid, NULL);
479 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
481 case OOMADJ_SERVICE_FOREGRD:
482 ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_DEFAULT);
485 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
496 void proc_set_group(pid_t onwerpid, pid_t childpid)
498 int oom_score_adj = 0;
499 struct proc_process_info_t *process_info =
500 find_process_info(NULL, onwerpid, NULL);
502 if (proc_get_oom_score_adj(onwerpid, &oom_score_adj) < 0) {
503 _D("owner pid(%d) was already terminated", onwerpid);
507 proc_add_pid_list(process_info, childpid, RESOURCED_APP_TYPE_GROUP);
508 proc_set_oom_score_adj(childpid, oom_score_adj);
512 pid_t find_pid_from_cmdline(char *cmdline)
514 pid_t pid = -1, foundpid = -1;
517 struct dirent *dentry;
518 char appname[PROC_NAME_MAX];
520 dp = opendir("/proc");
522 _E("BACKGRD MANAGE : fail to open /proc");
523 return RESOURCED_ERROR_FAIL;
525 while ((dentry = readdir(dp)) != NULL) {
526 if (!isdigit(dentry->d_name[0]))
529 pid = atoi(dentry->d_name);
532 ret = proc_get_cmdline(pid, appname);
533 if (ret == RESOURCED_ERROR_NONE) {
534 if (!strcmp(cmdline, appname)) {