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;;
58 struct dirent *result;
60 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
61 char appname[PROC_NAME_MAX];
63 int candidatepid[16] = {0,};
64 int cur_oom = -1, prev_oom=OOMADJ_BACKGRD_UNLOCKED, select_pid=0;
65 static int checkprevpid = 0;
66 unsigned long swap_args[2] = {0,};
67 unsigned long logging_args[3] = {0,};
69 ret = proc_get_cmdline(currentpid, appname);
70 if (ret == RESOURCED_ERROR_NONE) {
71 ret = resourced_proc_excluded(appname);
72 if (!active && !ret) {
73 proc_data.pid = currentpid;
74 proc_data.appid = appname;
75 resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD, &proc_data);
78 _D("BACKGRD MANAGE : don't manage background application by %d", currentpid);
79 return RESOURCED_ERROR_NONE;
83 dp = opendir("/proc");
85 _E("BACKGRD MANAGE : fail to open /proc");
86 return RESOURCED_ERROR_FAIL;
88 while (!(ret = readdir_r(dp, &dentry, &result)) && result != NULL) {
90 if (!isdigit(dentry.d_name[0]))
93 pid = atoi(dentry.d_name);
98 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
99 fp = fopen(buf, "r+");
102 if (fgets(buf, sizeof(buf), fp) == NULL) {
108 logging_args[0] = (unsigned long)pid;
109 logging_args[1] = (unsigned long)pgid;
110 logging_args[2] = (unsigned long)cur_oom;
111 logging_control(LOGGING_INSERT_PROC_LIST, logging_args);
113 if (currentpid != pid && currentpid == pgid) {
114 proc_set_group(currentpid, pid);
119 if (active || checkprevpid == currentpid) {
124 if (select_pid != pid && select_pid == pgid && count < 16)
126 _D("found candidate child pid = %d, pgid = %d", pid, pgid);
127 candidatepid[count++] = pid;
132 swap_args[0] = (unsigned long)pid;
133 if (cur_oom > OOMADJ_BACKGRD_UNLOCKED && cur_oom > prev_oom
134 && !swap_status(SWAP_CHECK_PID, swap_args)) {
136 candidatepid[count++] = pid;
141 if (cur_oom >= OOMADJ_APP_MAX) {
144 } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
145 _D("BACKGRD : process %d set score %d (before %d)",
146 pid, cur_oom+OOMADJ_APP_INCREASE, cur_oom);
147 fprintf(fp, "%d", cur_oom+OOMADJ_APP_INCREASE);
153 _E("BACKGRD MANAGE : readdir_r on /proc directory failed");
155 return RESOURCED_ERROR_FAIL;
159 _D("found candidate pid = %d, count = %d", candidatepid, count);
160 swap_args[0] = (unsigned long)candidatepid;
161 swap_args[1] = (unsigned long)count;
162 resourced_notify(RESOURCED_NOTIFIER_SWAP_SET_CANDIDATE_PID, swap_args);
164 checkprevpid = currentpid;
167 logging_control(LOGGING_UPDATE_PROC_INFO, NULL);
169 return RESOURCED_ERROR_NONE;
172 static int proc_foregrd_manage(int pid, int oom_score_adj)
176 struct proc_process_info_t *process_info =
177 find_process_info(NULL, pid, NULL);
180 ret = proc_set_oom_score_adj(pid, oom_score_adj);
184 gslist_for_each_item(iter, process_info->pids) {
185 struct pid_info_t *pid_info = (struct pid_info_t *)(iter->data);
186 ret = proc_set_oom_score_adj(pid_info->pid, oom_score_adj);
191 void proc_kill_victiom(gpointer key, gpointer value, gpointer user_data)
193 int pid = *(gint*)key;
195 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
198 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
199 fp = fopen(buf, "r+");
201 _D("sweep proc_kill_victim : background process %d already terminated", pid);
204 if (fgets(buf, sizeof(buf), fp) == NULL) {
209 if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
211 _D("sweep memory : background process %d killed by sigkill", pid);
216 static Eina_Bool proc_check_sweep_cb(void *data)
218 GHashTable *List = (GHashTable *)data;
219 g_hash_table_foreach(List, proc_kill_victiom, NULL);
220 g_hash_table_destroy(List);
221 proc_sweep_list = NULL;
222 return ECORE_CALLBACK_CANCEL;
225 int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
230 struct dirent dentry;
231 struct dirent *result;
234 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
235 char appname[PROC_NAME_MAX];
238 int select_sweep_limit;
239 dp = opendir("/proc");
241 _E("BACKGRD MANAGE : fail to open /proc");
242 return RESOURCED_ERROR_FAIL;
244 if (proc_sweep_timer)
245 ecore_timer_del(proc_sweep_timer);
247 g_hash_table_destroy(proc_sweep_list);
248 proc_sweep_list = g_hash_table_new(g_int_hash, g_int_equal);
250 if (type == PROC_SWEEP_EXCLUDE_ACTIVE)
251 select_sweep_limit = OOMADJ_BACKGRD_UNLOCKED;
253 select_sweep_limit = OOMADJ_BACKGRD_LOCKED;
255 while (!(ret = readdir_r(dp, &dentry, &result)) && result != NULL) {
256 if (!isdigit(dentry.d_name[0]))
259 pid = atoi(dentry.d_name);
263 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
264 fp = fopen(buf, "r+");
267 if (fgets(buf, sizeof(buf), fp) == NULL) {
272 if (cur_oom >= select_sweep_limit) {
273 ret = proc_get_cmdline(pid, appname);
278 proc_remove_process_list(pid);
279 piddata = g_new(gint, 1);
281 g_hash_table_insert(proc_sweep_list, piddata, NULL);
283 _D("sweep memory : background process %d(%s) killed",
290 _E("BACKGRD MANAGE : readdir_r call on /proc failed");
292 return RESOURCED_ERROR_FAIL;
296 ecore_timer_add(PROC_SWEEP_TIMER, proc_check_sweep_cb, (void *)proc_sweep_list);
303 int proc_get_cmdline(pid_t pid, char *cmdline)
305 char buf[PROC_BUF_MAX];
306 char cmdline_buf[PROC_NAME_MAX];
310 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
311 fp = fopen(buf, "r");
313 return RESOURCED_ERROR_FAIL;
315 if (fgets(cmdline_buf, PROC_NAME_MAX-1, fp) == NULL) {
317 return RESOURCED_ERROR_FAIL;
321 filename = strrchr(cmdline_buf, '/');
322 if (filename == NULL)
323 filename = cmdline_buf;
325 filename = filename + 1;
327 strncpy(cmdline, filename, PROC_NAME_MAX-1);
329 return RESOURCED_ERROR_NONE;
332 int proc_get_oom_score_adj(int pid, int *oom_score_adj)
334 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
338 return RESOURCED_ERROR_FAIL;
340 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
341 fp = fopen(buf, "r");
344 _E("fopen %s failed", buf);
345 return RESOURCED_ERROR_FAIL;
347 if (fgets(buf, sizeof(buf), fp) == NULL) {
349 return RESOURCED_ERROR_FAIL;
351 (*oom_score_adj) = atoi(buf);
353 return RESOURCED_ERROR_NONE;
356 int proc_set_oom_score_adj(int pid, int oom_score_adj)
358 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
360 unsigned long lowmem_args[2] = {0, };
362 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
363 fp = fopen(buf, "r+");
365 return RESOURCED_ERROR_FAIL;
366 if (fgets(buf, sizeof(buf), fp) == NULL) {
368 return RESOURCED_ERROR_FAIL;
370 fprintf(fp, "%d", oom_score_adj);
373 if (oom_score_adj >= OOMADJ_SU) {
374 lowmem_args[0] = (unsigned long)pid;
375 lowmem_args[1] = (unsigned long)oom_score_adj;
376 lowmem_control(LOWMEM_MOVE_CGROUP, lowmem_args);
381 int proc_set_foregrd(pid_t pid, int oom_score_adj)
385 switch (oom_score_adj) {
386 case OOMADJ_FOREGRD_LOCKED:
387 case OOMADJ_FOREGRD_UNLOCKED:
391 case OOMADJ_BACKGRD_LOCKED:
392 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_LOCKED);
394 case OOMADJ_BACKGRD_UNLOCKED:
396 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED);
399 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
400 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
410 int proc_set_backgrd(int pid, int oom_score_adj)
414 switch (oom_score_adj) {
415 case OOMADJ_BACKGRD_LOCKED:
416 case OOMADJ_BACKGRD_UNLOCKED:
420 case OOMADJ_FOREGRD_LOCKED:
421 proc_backgrd_manage(pid, PROC_BACKGROUND_ACTIVE);
422 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
424 case OOMADJ_FOREGRD_UNLOCKED:
425 proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE);
426 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
429 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
432 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
442 int proc_set_active(int pid, int oom_score_adj)
446 switch (oom_score_adj) {
447 case OOMADJ_FOREGRD_LOCKED:
448 case OOMADJ_BACKGRD_LOCKED:
451 /* don't change oom value pid */
454 case OOMADJ_FOREGRD_UNLOCKED:
455 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED);
457 case OOMADJ_BACKGRD_UNLOCKED:
458 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
460 case OOMADJ_SERVICE_DEFAULT:
461 case OOMADJ_SERVICE_BACKGRD:
462 ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_FOREGRD);
465 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED)
466 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED);
474 int proc_set_inactive(int pid, int oom_score_adj)
477 struct proc_process_info_t * processinfo;
478 switch (oom_score_adj) {
479 case OOMADJ_FOREGRD_UNLOCKED:
480 case OOMADJ_BACKGRD_UNLOCKED:
483 /* don't change oom value pid */
486 case OOMADJ_FOREGRD_LOCKED:
487 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED);
489 case OOMADJ_BACKGRD_LOCKED:
490 processinfo = find_process_info(NULL, pid, NULL);
492 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED);
494 case OOMADJ_SERVICE_FOREGRD:
495 ret = proc_set_oom_score_adj(pid, OOMADJ_SERVICE_DEFAULT);
498 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
509 void proc_set_group(pid_t onwerpid, pid_t childpid)
511 int oom_score_adj = 0;
512 struct proc_process_info_t *process_info =
513 find_process_info(NULL, onwerpid, NULL);
515 if (proc_get_oom_score_adj(onwerpid, &oom_score_adj) < 0) {
516 _D("owner pid(%d) was already terminated", onwerpid);
520 proc_add_pid_list(process_info, childpid, RESOURCED_APP_TYPE_GROUP);
521 proc_set_oom_score_adj(childpid, oom_score_adj);
525 pid_t find_pid_from_cmdline(char *cmdline)
527 pid_t pid = -1, foundpid = -1;
530 struct dirent dentry;
531 struct dirent *result;
532 char appname[PROC_NAME_MAX];
534 dp = opendir("/proc");
536 _E("BACKGRD MANAGE : fail to open /proc");
537 return RESOURCED_ERROR_FAIL;
539 while (!(ret = readdir_r(dp, &dentry, &result)) && result != NULL) {
540 if (!isdigit(dentry.d_name[0]))
543 pid = atoi(dentry.d_name);
546 ret = proc_get_cmdline(pid, appname);
547 if (ret == RESOURCED_ERROR_NONE) {
548 if (!strcmp(cmdline, appname)) {
556 _E("BACKGRD MANAGE : readdir_r call on /proc directory failed");
557 return RESOURCED_ERROR_FAIL;