#include <eventsystem.h>
#include "lowmem.h"
+#include "lowmem-limit.h"
#include "proc-common.h"
#include "proc-main.h"
#include "resourced.h"
return RESOURCED_ERROR_NONE;
}
+static void swap_activate_act(void)
+{
+ int ret, status;
+
+ ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
+ if (ret)
+ _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
+
+ if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
+ vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
+ VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
+ lowmem_memory_level_send_system_event(MEM_LEVEL_LOW);
+ }
+ lowmem_change_lowmem_state(MEM_LEVEL_LOW);
+ if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
+ resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
+ (void *)CGROUP_FREEZER_ENABLED);
+
+ if (swap_get_state() != SWAP_ON)
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
+}
+
+static void lowmem_swap_memory(char *path)
+{
+ /* The services cannot call this function but the apps can. */
+ unsigned int available_mb;
+ unsigned int cur_mem_state;
+
+ cur_mem_state = lowmem_get_lowmem_state();
+ if (cur_mem_state == MEM_LEVEL_HIGH)
+ return;
+
+ if (swap_get_state() != SWAP_ON)
+ return;
+
+ available_mb = proc_get_mem_available();
+ if (cur_mem_state != MEM_LEVEL_LOW &&
+ available_mb <= get_root_memcg_info()->threshold_mb[MEM_LEVEL_LOW])
+ swap_activate_act();
+
+ resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
+ lowmem_set_memcg_swap_status(true);
+}
+
+static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
+{
+ int cur_oom_score_adj;
+ int cur_memcg_idx;
+ struct memcg_info *mi;
+ int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
+
+ mi = get_memcg_info(next_memcg_idx);
+
+ if (!mi)
+ return;
+
+ if (!pai) {
+ cgroup_write_pid_fullpath(mi->name, pid);
+ return;
+ }
+
+ if (pai->main_pid == pid) {
+ /* parent pid */
+ cur_oom_score_adj = pai->memory.oom_score_adj;
+ cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
+
+ if (cur_oom_score_adj == next_oom_score_adj) {
+ _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
+ return;
+ }
+
+ proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
+
+ if (!lowmem_limit_move_cgroup(pai))
+ return;
+
+ if(cur_memcg_idx == next_memcg_idx)
+ return;
+
+ _I("app (%s) memory cgroup move from %s to %s", pai->appid,
+ lowmem_convert_cgroup_type_to_str(cur_memcg_idx),
+ lowmem_convert_cgroup_type_to_str(next_memcg_idx));
+
+ cgroup_write_pid_fullpath(mi->name, pid);
+ if (next_memcg_idx == MEMCG_THROTTLING)
+ lowmem_swap_memory(get_memcg_info(MEMCG_THROTTLING)->name);
+ } else {
+ /* child pid */
+ if (pai->memory.use_mem_limit)
+ return;
+
+ cgroup_write_pid_fullpath(mi->name, pid);
+ }
+}
+
+int lowmem_control_handler(void *data)
+{
+ struct lowmem_control_data *lowmem_data = (struct lowmem_control_data *)data;
+
+ switch (lowmem_data->control_type) {
+ case LOWMEM_MOVE_CGROUP:
+ lowmem_move_memcgroup((pid_t)lowmem_data->pid,
+ lowmem_data->oom_score_adj,
+ lowmem_data->pai);
+ break;
+ default:
+ break;
+ }
+
+ return RESOURCED_ERROR_NONE;
+}
+
/* lowmem actions */
static int high_mem_act(void *data)
{
return RESOURCED_ERROR_NONE;
}
+static int low_mem_act(void *data)
+{
+ swap_activate_act();
+
+ return RESOURCED_ERROR_NONE;
+}
static int critical_mem_act(void *data)
{
int scan_mode = KSM_SCAN_FULL;
/* Initialize actions for the memory levels */
lowmem_initialize_controller_ops_action(MEM_LEVEL_HIGH, high_mem_act);
lowmem_initialize_controller_ops_action(MEM_LEVEL_MEDIUM, medium_mem_act);
+ lowmem_initialize_controller_ops_action(MEM_LEVEL_LOW, low_mem_act);
lowmem_initialize_controller_ops_action(MEM_LEVEL_CRITICAL, critical_mem_act);
+ register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
+
return RESOURCED_ERROR_NONE;
}
static int lowmem_controller_finalize(void *data)
{
+ unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
+
return RESOURCED_ERROR_NONE;
}
/* Initialize governors for the memory levels */
lowmem_initialize_controller_ops_governor(MEM_LEVEL_HIGH, mem_state_dummy_governor);
lowmem_initialize_controller_ops_governor(MEM_LEVEL_MEDIUM, mem_state_dummy_governor);
+ lowmem_initialize_controller_ops_governor(MEM_LEVEL_LOW, mem_state_dummy_governor);
lowmem_initialize_controller_ops_governor(MEM_LEVEL_CRITICAL, mem_state_dummy_governor);
return RESOURCED_ERROR_NONE;
/* low memory action function for cgroup */
/* low memory action function */
-static void swap_activate_act(void);
static void swap_compact_act(void);
static void lmk_act(void);
switch (mem_state) {
case MEM_LEVEL_HIGH:
case MEM_LEVEL_MEDIUM:
+ case MEM_LEVEL_LOW:
case MEM_LEVEL_CRITICAL:
lowmem_actions[mem_state].governor = governor;
return;
pthread_exit(NULL);
}
+unsigned int lowmem_get_lowmem_state()
+{
+ return cur_mem_state;
+}
void lowmem_change_lowmem_state(unsigned int mem_state)
{
cur_mem_state = mem_state;
(void *)&cur_mem_state);
}
-/* only app can call this function
- * that is, service cannot call the function
- */
-static void lowmem_swap_memory(char *path)
-{
- unsigned int available_mb;
-
- if (cur_mem_state == MEM_LEVEL_HIGH)
- return;
-
- if (swap_get_state() != SWAP_ON)
- return;
-
- available_mb = proc_get_mem_available();
- if (cur_mem_state != MEM_LEVEL_LOW &&
- available_mb <= get_root_memcg_info()->threshold_mb[MEM_LEVEL_LOW])
- swap_activate_act();
-
- resourced_notify(RESOURCED_NOTIFIER_SWAP_START, path);
- memcg_swap_status = true;
-}
-
void lowmem_trigger_swap(pid_t pid, char *path, bool move)
{
int error;
bundle_free(b);
}
-static void swap_activate_act(void)
-{
- int ret, status;
-
- ret = vconf_get_int(VCONFKEY_SYSMAN_LOW_MEMORY, &status);
- if (ret)
- _E("vconf get failed %s", VCONFKEY_SYSMAN_LOW_MEMORY);
-
- if (status != VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL) {
- vconf_set_int(VCONFKEY_SYSMAN_LOW_MEMORY,
- VCONFKEY_SYSMAN_LOW_MEMORY_NORMAL);
- lowmem_memory_level_send_system_event(MEM_LEVEL_LOW);
- }
- lowmem_change_lowmem_state(MEM_LEVEL_LOW);
- if (proc_get_freezer_status() == CGROUP_FREEZER_PAUSED)
- resourced_notify(RESOURCED_NOTIFIER_FREEZER_CGROUP_STATE,
- (void *)CGROUP_FREEZER_ENABLED);
-
- if (swap_get_state() != SWAP_ON)
- resourced_notify(RESOURCED_NOTIFIER_SWAP_ACTIVATE, NULL);
-}
-
static void swap_compact_act(void)
{
lowmem_change_lowmem_state(MEM_LEVEL_CRITICAL);
switch (mem_state) {
case MEM_LEVEL_HIGH:
case MEM_LEVEL_MEDIUM:
+ case MEM_LEVEL_LOW:
assert(lowmem_actions[mem_state].governor != NULL);
assert(lowmem_actions[mem_state].action != NULL);
if (lowmem_actions[mem_state].governor(NULL) < 0)
break;
lowmem_actions[mem_state].action(NULL);
break;
- case MEM_LEVEL_LOW:
- swap_activate_act();
- break;
case MEM_LEVEL_CRITICAL:
assert(lowmem_actions[mem_state].governor != NULL);
assert(lowmem_actions[mem_state].action != NULL);
}
}
-static void lowmem_move_memcgroup(int pid, int next_oom_score_adj, struct proc_app_info *pai)
-{
- int cur_oom_score_adj;
- int cur_memcg_idx;
- struct memcg_info *mi;
- int next_memcg_idx = cgroup_get_type(next_oom_score_adj);
-
- mi = get_memcg_info(next_memcg_idx);
-
- if (!mi) {
- return;
- }
-
- if (!pai) {
- cgroup_write_pid_fullpath(mi->name, pid);
- return;
- }
-
- /* parent pid */
- if (pai->main_pid == pid) {
- cur_oom_score_adj = pai->memory.oom_score_adj;
- cur_memcg_idx = cgroup_get_type(cur_oom_score_adj);
-
- if (cur_oom_score_adj == next_oom_score_adj) {
- _D("next oom_score_adj (%d) is same with current one", next_oom_score_adj);
- return;
- }
-
- proc_set_process_memory_state(pai, next_memcg_idx, mi, next_oom_score_adj);
-
- if (!lowmem_limit_move_cgroup(pai))
- return;
-
- if(cur_memcg_idx == next_memcg_idx)
- return;
-
- _I("app (%s) memory cgroup move from %s to %s", pai->appid, lowmem_convert_cgroup_type_to_str(cur_memcg_idx), lowmem_convert_cgroup_type_to_str(next_memcg_idx));
- cgroup_write_pid_fullpath(mi->name, pid);
- if (next_memcg_idx == MEMCG_THROTTLING)
- lowmem_swap_memory(get_memcg_info(MEMCG_THROTTLING)->name);
- }
- /* child pid */
- else {
- if (pai->memory.use_mem_limit)
- return;
-
- cgroup_write_pid_fullpath(mi->name, pid);
- }
-}
-
static int lowmem_activate_worker(void)
{
int ret = RESOURCED_ERROR_NONE;
return RESOURCED_ERROR_NONE;
}
-int lowmem_control_handler(void *data)
-{
- struct lowmem_control_data *lowmem_data;
-
- lowmem_data = (struct lowmem_control_data *)data;
- switch (lowmem_data->control_type) {
- case LOWMEM_MOVE_CGROUP:
- lowmem_move_memcgroup((pid_t)lowmem_data->pid,
- lowmem_data->oom_score_adj, lowmem_data->pai);
- break;
- default:
- break;
- }
- return RESOURCED_ERROR_NONE;
-}
-
static inline int calculate_threshold_size(double ratio)
{
unsigned long long size_bytes = (double)totalram_bytes * ratio / 100.0;
lowmem_system_init();
register_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
- register_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
return ret;
}
lowmem_system_exit();
unregister_notifier(RESOURCED_NOTIFIER_APP_PRELAUNCH, lowmem_prelaunch_handler);
- unregister_notifier(RESOURCED_NOTIFIER_MEM_CONTROL, lowmem_control_handler);
return RESOURCED_ERROR_NONE;
}
void(*)(void)));
void lowmem_initialize_controller_ops_governor(int mem_state, int (*governor)(void *data));
void lowmem_initialize_controller_ops_action(int mem_state, int (*action)(void *data));
+unsigned int lowmem_get_lowmem_state();
void lowmem_change_lowmem_state(unsigned int mem_state);
void lowmem_memory_level_send_system_event(int lv);
bool lowmem_get_memcg_swap_status();