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"
36 #include "memory-cgroup.h"
39 #include "proc-appusage.h"
40 #include "safe-kill.h"
42 #define PROC_SWEEP_TIMER 3
43 static GHashTable *proc_sweep_list;
44 static GSource *proc_sweep_timer;
46 enum proc_background_type {
47 PROC_BACKGROUND_INACTIVE,
48 PROC_BACKGROUND_ACTIVE,
51 int proc_set_service_oomscore(const pid_t pid, const int oom_score, struct proc_app_info *pai)
54 if (oom_score > 0 && oom_score != OOMADJ_SERVICE_DEFAULT)
55 service_oom = oom_score - OOMADJ_SERVICE_GAP;
57 service_oom = OOMADJ_SERVICE_DEFAULT;
58 return proc_set_oom_score_adj(pid, service_oom, pai);
61 static void proc_set_oom_score_childs(struct proc_app_info *pai, int oom_score_adj)
71 gslist_for_each_item(iter, pai->childs) {
72 proc_set_oom_score_adj(GPOINTER_TO_PID(iter->data), oom_score_adj, pai);
76 static void proc_set_oom_score_services(int state, GSList *svcs,
84 gslist_for_each_item(iter, svcs) {
85 struct proc_app_info *svc = (struct proc_app_info *)(iter->data);
87 proc_set_service_oomscore(svc->main_pid, oom_score_adj, svc);
91 static int proc_get_lowest_oom_score(GSList *uiapps)
94 int min_oom_score = OOMADJ_APP_MAX;
95 int oom_score_adj = 0, ret;
100 gslist_for_each_item(iter, uiapps) {
101 struct proc_app_info *pai = (struct proc_app_info *)(iter->data);
103 ret = proc_get_oom_score_adj(pai->main_pid, &oom_score_adj);
106 min_oom_score = (oom_score_adj < min_oom_score) ? oom_score_adj : min_oom_score;
109 return min_oom_score;
112 static int proc_backgrd_manage(int currentpid, int active, int oom_score_adj, struct proc_app_info *pai)
115 int flag = RESOURCED_NOTIFIER_APP_BACKGRD;
116 struct proc_status ps;
118 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
120 static int checkprevpid;
123 struct proc_program_info *ppi;
126 if (proc_get_freezer_status() != CGROUP_FREEZER_DISABLED)
127 freeze_val = resourced_freezer_proc_late_control();
130 _E("can't find app info about pid %d", currentpid);
131 return RESOURCED_ERROR_INVALID_PARAMETER;
135 * About groupd process with multiple applications,
136 * all application with same group could be went to background state.
137 * If one application has already managed to background application
138 * it skipped to go to the background again.
140 if (pai->lru_state >= PROC_BACKGROUND) {
141 _D("pid %d already in background", currentpid);
142 return RESOURCED_ERROR_NONE;
148 flag = RESOURCED_NOTIFIER_APP_BACKGRD_ACTIVE;
149 resourced_notify(flag, &ps);
154 pai->lru_state = PROC_BACKGROUND;
155 if (proc_check_favorite_app(pai->appid)) {
156 _D("detect favorite application : %s", pai->appid);
157 oom_score_adj = OOMADJ_FAVORITE;
158 pai->lru_state = PROC_FAVORITE;
162 if (checkprevpid != currentpid) {
163 _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
165 proc_app_list = proc_app_list_open();
166 gslist_for_each_item(iter, proc_app_list) {
167 struct proc_app_info *spi = (struct proc_app_info *)iter->data;
169 int lru_offset = freeze_val;
171 if (!spi->main_pid || spi->type != PROC_TYPE_GUI)
175 * It checks all applications from proc_app_list
176 * So, current background process can be checked again.
177 * It is because lru value of this application was already changed,
178 * it should be skipped
185 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
186 fp = fopen(buf, "r+");
191 if (fgets(buf, sizeof(buf), fp) == NULL) {
198 if (spi->lru_state == PROC_BACKGROUND ||
199 spi->lru_state == PROC_FAVORITE) {
200 memset(&ps, 0, sizeof(struct proc_status));
204 RESOURCED_NOTIFIER_APP_SUSPEND_READY,
208 * clear lru offset if platform controls background application
210 if (spi->flags & PROC_BGCTRL_PLATFORM)
213 if (proc_check_lru_suspend(lru_offset, spi->lru_state) &&
214 (proc_check_suspend_state(spi) == PROC_STATE_SUSPEND)) {
215 memset(&ps, 0, sizeof(struct proc_status));
219 RESOURCED_NOTIFIER_APP_SUSPEND,
224 if (spi->lru_state >= PROC_FAVORITE &&
225 spi->lru_state < PROC_FAVORITE_LRU_MAX) {
227 _D("FAVORITE : process %d increase lru %d",
228 pid, spi->lru_state - PROC_FAVORITE + 1);
231 if (cur_oom >= OOMADJ_FAVORITE &&
232 cur_oom < OOMADJ_FAVORITE_APP_MAX) {
233 new_oom = cur_oom + OOMADJ_FAVORITE_APP_INCREASE;
234 _D("FAVORITE : process %d set score %d (beford %d)",
235 pid, new_oom, cur_oom);
236 proc_set_oom_score_adj(pid, new_oom, spi);
237 proc_set_oom_score_childs(spi, new_oom);
240 if (spi->lru_state >= PROC_BACKGROUND &&
241 spi->lru_state < PROC_LRU_MAX) {
243 _D("BACKGRD : process %d increase lru %d", pid, spi->lru_state);
246 if (cur_oom >= OOMADJ_APP_MAX) {
249 } else if (cur_oom >= OOMADJ_BACKGRD_UNLOCKED) {
250 new_oom = cur_oom + OOMADJ_APP_INCREASE;
251 _D("BACKGRD : process %d set score %d (before %d)",
252 pid, new_oom, cur_oom);
253 proc_set_oom_score_adj(pid, new_oom, spi);
254 proc_set_oom_score_childs(spi, new_oom);
262 proc_set_oom_score_adj(pai->main_pid, oom_score_adj, pai);
264 /* change oom score about child pids */
265 proc_set_oom_score_childs(pai, oom_score_adj);
267 /* change oom score about grouped service processes */
269 if (ppi && proc_get_svc_state(ppi) == PROC_STATE_BACKGROUND)
270 proc_set_oom_score_services(PROC_STATE_BACKGROUND, ppi->svc_list,
271 (proc_get_lowest_oom_score(ppi->app_list) >= oom_score_adj) ? OOMADJ_BACKGRD_UNLOCKED : OOMADJ_SERVICE_DEFAULT);
273 checkprevpid = currentpid;
274 return RESOURCED_ERROR_NONE;
277 static int proc_foregrd_manage(int pid, int oom_score_adj, struct proc_app_info *pai)
280 struct proc_program_info *ppi;
283 _E("process app info is NULL");
284 proc_set_oom_score_adj(pid, oom_score_adj, pai);
285 return RESOURCED_ERROR_NO_DATA;
288 proc_set_oom_score_adj(pai->main_pid, oom_score_adj, pai);
290 /* change oom score about child pids */
291 proc_set_oom_score_childs(pai, oom_score_adj);
293 pai->lru_state = PROC_FOREGROUND;
295 /* change oom score about grouped service processes */
298 proc_set_oom_score_services(PROC_STATE_FOREGROUND, ppi->svc_list,
304 void proc_kill_victiom(gpointer key, gpointer value, gpointer user_data)
306 int pid = *(gint *)key;
308 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
311 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
312 fp = fopen(buf, "r+");
314 _D("sweep proc_kill_victim : background process %d already terminated", pid);
317 if (fgets(buf, sizeof(buf), fp) == NULL) {
322 if (cur_oom >= OOMADJ_FAVORITE) {
323 safe_kill(pid, SIGKILL);
324 _D("sweep memory : background process %d killed by sigkill", pid);
329 static gboolean proc_check_sweep_cb(gpointer data)
331 GHashTable *List = (GHashTable *)data;
332 g_hash_table_foreach(List, proc_kill_victiom, NULL);
333 g_hash_table_destroy(List);
334 proc_sweep_list = NULL;
339 int proc_sweep_memory(enum proc_sweep_type type, pid_t callpid)
341 _cleanup_app_list_close_ GSList *proc_app_list = PAL_INIT_VALUE;
346 char buf[sizeof(PROC_OOM_SCORE_ADJ_PATH) + MAX_DEC_SIZE(int)] = {0};
347 char appname[PROC_NAME_MAX];
350 int select_sweep_limit;
352 struct proc_app_info *pai;
354 if (proc_sweep_timer)
355 g_source_destroy(proc_sweep_timer);
357 g_hash_table_destroy(proc_sweep_list);
358 proc_sweep_list = g_hash_table_new(g_int_hash, g_int_equal);
360 if (type == PROC_SWEEP_EXCLUDE_ACTIVE)
361 select_sweep_limit = OOMADJ_FAVORITE;
363 select_sweep_limit = OOMADJ_BACKGRD_LOCKED;
365 proc_app_list = proc_app_list_open();
366 gslist_for_each_item(iter, proc_app_list) {
367 pai = (struct proc_app_info *)iter->data;
368 if (!pai->main_pid || pai->type != PROC_TYPE_GUI)
373 snprintf(buf, sizeof(buf), PROC_OOM_SCORE_ADJ_PATH, pid);
374 fp = fopen(buf, "r+");
377 if (fgets(buf, sizeof(buf), fp) == NULL) {
382 if (cur_oom >= select_sweep_limit) {
383 ret = proc_get_cmdline(pid, appname, sizeof appname);
388 resourced_proc_status_change(PROC_CGROUP_SET_TERMINATE_REQUEST,
389 pid, NULL, NULL, PROC_TYPE_NONE);
390 piddata = g_new(gint, 1);
392 g_hash_table_insert(proc_sweep_list, piddata, NULL);
393 safe_kill(pid, SIGTERM);
394 _D("sweep memory : background process %d(%s) killed",
401 proc_sweep_timer = g_timeout_source_new_seconds(PROC_SWEEP_TIMER);
402 g_source_set_callback(proc_sweep_timer, proc_check_sweep_cb, (gpointer)proc_sweep_list, NULL);
403 g_source_attach(proc_sweep_timer, NULL);
409 int proc_set_foregrd(pid_t pid, int oom_score_adj, struct proc_app_info *pai)
413 switch (oom_score_adj) {
414 case OOMADJ_FOREGRD_UNLOCKED:
418 case OOMADJ_FOREGRD_LOCKED:
419 case OOMADJ_BACKGRD_LOCKED:
420 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_LOCKED, pai);
422 case OOMADJ_BACKGRD_UNLOCKED:
424 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED, pai);
427 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED ||
428 (oom_score_adj >= OOMADJ_FAVORITE &&
429 oom_score_adj <= OOMADJ_FAVORITE_APP_MAX))
430 ret = proc_foregrd_manage(pid, OOMADJ_FOREGRD_UNLOCKED, pai);
439 static int check_oom_score_for_backgrd(int pid, int oom_score_adj, struct proc_app_info *pai)
441 struct proc_status ps;
446 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED)
455 if (proc_oom_priority_is_oom_fixed_process(pid)) {
456 resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD_WITH_FIXED_OOM_SCORE, &ps);
460 if (oom_score_adj == OOMADJ_BACKGRD_PERCEPTIBLE) {
461 resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD_WITH_FIXED_OOM_SCORE, &ps);
468 int proc_set_backgrd(int pid, int oom_score_adj, struct proc_app_info *pai)
472 switch (oom_score_adj) {
473 case OOMADJ_BACKGRD_LOCKED:
474 case OOMADJ_BACKGRD_UNLOCKED:
478 case OOMADJ_FOREGRD_LOCKED:
479 ret = proc_backgrd_manage(pid, PROC_BACKGROUND_ACTIVE, OOMADJ_BACKGRD_LOCKED, pai);
481 case OOMADJ_FOREGRD_UNLOCKED:
483 ret = proc_backgrd_manage(pid, PROC_BACKGROUND_INACTIVE, OOMADJ_BACKGRD_UNLOCKED, pai);
486 ret = check_oom_score_for_backgrd(pid, oom_score_adj, pai);
492 int proc_set_active(int pid, int oom_score_adj)
495 struct proc_app_info *pai;
497 switch (oom_score_adj) {
498 case OOMADJ_FOREGRD_LOCKED:
499 case OOMADJ_BACKGRD_LOCKED:
501 /* don't change oom value pid */
505 case OOMADJ_FOREGRD_UNLOCKED:
506 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_LOCKED, find_app_info(pid));
508 case OOMADJ_BACKGRD_UNLOCKED:
509 pai = find_app_info(pid);
511 pai->lru_state = PROC_ACTIVE;
512 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED, pai);
514 case OOMADJ_PREVIOUS_BACKGRD:
515 ret = proc_set_oom_score_adj(pid, OOMADJ_PREVIOUS_DEFAULT, find_app_info(pid));
518 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED) {
519 pai = find_app_info(pid);
521 pai->lru_state = PROC_ACTIVE;
522 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_LOCKED, pai);
530 int proc_set_inactive(int pid, int oom_score_adj)
533 struct proc_app_info *pai;
534 switch (oom_score_adj) {
535 case OOMADJ_FOREGRD_UNLOCKED:
536 case OOMADJ_BACKGRD_UNLOCKED:
539 /* don't change oom value pid */
542 case OOMADJ_FOREGRD_LOCKED:
543 ret = proc_set_oom_score_adj(pid, OOMADJ_FOREGRD_UNLOCKED, find_app_info(pid));
545 case OOMADJ_BACKGRD_LOCKED:
546 pai = find_app_info(pid);
548 struct proc_status ps = {0};
551 pai->lru_state = PROC_BACKGROUND;
552 ret = proc_set_oom_score_adj(pid, OOMADJ_BACKGRD_UNLOCKED, pai);
553 resourced_notify(RESOURCED_NOTIFIER_APP_BACKGRD, &ps);
554 struct proc_program_info *const ppi = pai->program;
555 if (ppi && proc_get_svc_state(ppi) == PROC_STATE_BACKGROUND)
556 proc_set_oom_score_services(PROC_STATE_BACKGROUND, ppi->svc_list,
557 (proc_get_lowest_oom_score(ppi->app_list) >= oom_score_adj) ? OOMADJ_BACKGRD_UNLOCKED : OOMADJ_SERVICE_DEFAULT);
561 if (oom_score_adj > OOMADJ_BACKGRD_UNLOCKED)