*
*/
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
#include <Ecore.h>
#include <Ecore_File.h>
#include <pthread.h>
#include "procfs.h"
#include "appinfo-list.h"
#include "util.h"
+#include "file-helper.h"
#include "config-parser.h"
static GHashTable *proc_exclude_list;
return false;
}
+static char *proc_get_runtime_app_info_path(const struct proc_app_info *pai)
+{
+ char *p = NULL;
+
+ assert(pai);
+ assert(pai->appid);
+
+ if (asprintf(&p, RUNTIME_APP_INFO_DIR "/%s", pai->appid) < 0)
+ return NULL;
+
+ return p;
+}
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_WRITE_STR(node) \
+ int proc_runtime_app_info_write_##node(const char *path, \
+ const char *data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ assert(data); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fwrite_str(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_READ_STR(node) \
+ int proc_runtime_app_info_read_##node(const char *path, \
+ char **data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ assert(data); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fread_str(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(node) \
+ int proc_runtime_app_info_write_##node(const char *path, \
+ int32_t data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fwrite_int(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(node) \
+ int proc_runtime_app_info_read_##node(const char *path, \
+ int32_t *data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ assert(data); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fread_int(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_WRITE_UINT32(node) \
+ int proc_runtime_app_info_write_##node(const char *path, \
+ uint32_t data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fwrite_uint(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_READ_UINT32(node) \
+ int proc_runtime_app_info_read_##node(const char *path, \
+ uint32_t *data) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ \
+ assert(path); \
+ assert(data); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ return fread_uint(app_info_node, data); \
+ }
+
+#define DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(node) \
+ int proc_runtime_app_info_remove_##node(const char *path) \
+ { \
+ char app_info_node[PATH_MAX] = ""; \
+ int ret; \
+ \
+ assert(path); \
+ \
+ snprintf(app_info_node, PATH_MAX, "%s/"#node"", path); \
+ \
+ ret = unlink(app_info_node); \
+ if (ret < 0) \
+ return -errno; \
+ \
+ return ret; \
+ }
+
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_STR(appid);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_STR(appid);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_UINT32(main_pid);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_UINT32(main_pid);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(runtime_exclude);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(runtime_exclude);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(flags);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(flags);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(lru_state);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(lru_state);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(categories);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(categories);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(state);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(state);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_INT32(type);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_INT32(type);
+DEFINE_PROC_RUNTIME_APP_INFO_WRITE_STR(pkgname);
+DEFINE_PROC_RUNTIME_APP_INFO_READ_STR(pkgname);
+
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(appid);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(procs);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(main_pid);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(runtime_exclude);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(flags);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(lru_state);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(categories);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(state);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(type);
+DEFINE_PROC_RUNTIME_APP_INFO_REMOVE(pkgname);
+
+static int proc_runtime_app_info_write_procs(const char *path, pid_list child_list)
+{
+ char app_info_node[PATH_MAX] = "";
+ _cleanup_fclose_ FILE *f = NULL;
+ pid_list list = child_list;
+
+ assert(path);
+
+ if (!child_list)
+ return 0;
+
+ snprintf(app_info_node, PATH_MAX, "%s/procs", path);
+
+ f = fopen(app_info_node, "w");
+ if (!f)
+ return -errno;
+
+ (void) fprintf(f, "%d", GPOINTER_TO_PID(child_list->data));
+
+ for (list = g_slist_next(list); list; list = g_slist_next(list))
+ (void) fprintf(f, " %d", GPOINTER_TO_PID(list->data));
+
+ return 0;
+}
+
+static int proc_runtime_app_info_read_procs(const char *path, pid_list *child_list)
+{
+ char app_info_node[PATH_MAX] = "";
+ _cleanup_free_ char *buf = NULL;
+ pid_list list = NULL;
+ char *word, *state;
+ size_t len;
+ int ret;
+
+ assert(path);
+ assert(child_list);
+
+ snprintf(app_info_node, PATH_MAX, "%s/procs", path);
+
+ ret = fread_str(app_info_node, &buf);
+ if (ret < 0)
+ return ret;
+
+ FOREACH_WORD(word, len, buf, state) {
+ _cleanup_free_ char *pid_s = NULL;
+ pid_t pid;
+
+ pid_s = strndup(word, len);
+ if (!pid_s)
+ goto on_error;
+
+ pid = atoi(pid_s);
+
+ list = g_slist_prepend(list, PID_TO_GPOINTER(pid));
+ }
+
+ *child_list = list;
+
+ return 0;
+
+on_error:
+ g_slist_free(list);
+
+ return -ENOMEM;
+}
+
void proc_add_child_pid(struct proc_app_info *pai, pid_t pid)
{
+ _cleanup_free_ char *runtime_app_info_path = NULL;
+ int ret;
+
assert(pai);
assert(pid > 0);
return;
pai->childs = g_slist_prepend(pai->childs, PID_TO_GPOINTER(pid));
+
+ runtime_app_info_path = proc_get_runtime_app_info_path(pai);
+ if (!runtime_app_info_path) {
+ _E("Failed to get runtime appinfo path: %s", strerror(ENOMEM));
+ return;
+ }
+
+ ret = proc_runtime_app_info_write_procs(runtime_app_info_path, pai->childs);
+ if (ret < 0)
+ _E("Failed to write appinfo children '%s': %s",
+ runtime_app_info_path, strerror(-ret));
}
void proc_set_process_memory_state(struct proc_app_info *pai,
resourced_ret_c proc_set_runtime_exclude_list(const int pid, int type)
{
+ _cleanup_free_ char *runtime_app_info_path = NULL;
struct proc_app_info *pai = NULL;
struct proc_status ps = {0};
+ int ret;
pai = find_app_info(pid);
if (!pai)
_D("pid %d set proc exclude list, type = %d, exclude = %d",
pid, type, pai->runtime_exclude);
+ runtime_app_info_path = proc_get_runtime_app_info_path(pai);
+ if (!runtime_app_info_path)
+ return RESOURCED_ERROR_OUT_OF_MEMORY;
+
+ ret = proc_runtime_app_info_write_runtime_exclude(runtime_app_info_path, pai->runtime_exclude);
+ if (ret < 0)
+ return RESOURCED_ERROR_FAIL;
+
return RESOURCED_ERROR_NONE;
}
}
}
proc_program_list = g_slist_prepend(proc_program_list, ppi);
+ _I("%s is added in the program info", pkgname);
}
if (is_ui_app(type))
ppi->app_list = g_slist_prepend(ppi->app_list, pai);
return ppi;
}
+static int proc_runtime_write_app_info(const struct proc_app_info *pai)
+{
+ _cleanup_free_ char *runtime_app_info_path = NULL;
+ int ret;
+
+ assert(pai);
+ assert(pai->appid);
+
+ runtime_app_info_path = proc_get_runtime_app_info_path(pai);
+ if (!runtime_app_info_path)
+ return -ENOMEM;
+
+ ret = mkdir(runtime_app_info_path, S_IRWXU | S_IRGRP | S_IXGRP);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_appid(runtime_app_info_path, pai->appid);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_main_pid(runtime_app_info_path, pai->main_pid);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_procs(runtime_app_info_path, pai->childs);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_runtime_exclude(runtime_app_info_path, pai->runtime_exclude);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_flags(runtime_app_info_path, pai->flags);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_lru_state(runtime_app_info_path, pai->lru_state);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_categories(runtime_app_info_path, pai->categories);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_state(runtime_app_info_path, pai->state);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_write_type(runtime_app_info_path, pai->type);
+ if (ret < 0)
+ return ret;
+
+ if (!pai->program)
+ return 0;
+
+ return proc_runtime_app_info_write_pkgname(runtime_app_info_path, pai->program->pkgname);
+}
+
+static int proc_runtime_remove_app_info(const struct proc_app_info *pai)
+{
+ _cleanup_free_ char *runtime_app_info_path = NULL;
+ int ret;
+ DIR *dir;
+
+ assert(pai);
+ assert(pai->appid);
+
+ runtime_app_info_path = proc_get_runtime_app_info_path(pai);
+ if (!runtime_app_info_path)
+ return -ENOMEM;
+
+ dir = opendir(runtime_app_info_path);
+ if (!dir)
+ return -ENOTDIR;
+ closedir(dir);
+
+ ret = proc_runtime_app_info_remove_appid(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_main_pid(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_procs(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_runtime_exclude(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_flags(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_lru_state(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_categories(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_state(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_type(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+ ret = proc_runtime_app_info_remove_pkgname(runtime_app_info_path);
+ if (ret < 0 && ret != -ENOENT)
+ goto finish;
+
+finish:
+ if (rmdir(runtime_app_info_path) < 0)
+ return -errno;
+
+ return ret == -ENOENT ? 0 : ret;
+}
+
struct proc_app_info *proc_add_app_list(const int type, const pid_t pid,
const char *appid, const char *pkgname)
{
struct proc_app_info *pai;
+ int ret;
if (!appid)
return NULL;
pai->main_pid = pid;
pai->program = proc_add_program_list(type, pai, pkgname);
pai->state = PROC_STATE_FOREGROUND;
+
+ ret = proc_runtime_write_app_info(pai);
+ if (ret < 0)
+ _E("Failed to add runtime app info: %s", strerror(ret));
+
return pai;
}
static void _remove_child_pids(struct proc_app_info *pai, pid_t pid)
{
+ _cleanup_free_ char *runtime_app_info_path = NULL;
GSList *iter, *next;
pid_t *child;
+ int ret;
assert(pai);
assert(pid >= 0);
if (!g_slist_find(pai->childs, PID_TO_GPOINTER(pid)))
return;
+
+ runtime_app_info_path = proc_get_runtime_app_info_path(pai);
+ if (!runtime_app_info_path) {
+ _E("Failed to get runtime appinfo path: %s", strerror(ENOMEM));
+ return;
+ }
+
+ if (pid == 0)
+ goto remove_all;
+
+ pai->childs = g_slist_remove(pai->childs, PID_TO_GPOINTER(pid));
+ if (!g_slist_length(pai->childs))
+ goto remove_all;
+
+ ret = proc_runtime_app_info_write_procs(runtime_app_info_path, pai->childs);
+ if (ret < 0)
+ _E("Failed to write appinfo children '%s': %s",
+ runtime_app_info_path, strerror(-ret));
+
+ return;
+
+remove_all:
+ g_slist_free(pai->childs);
+ pai->childs = NULL;
+
+ ret = proc_runtime_app_info_remove_procs(runtime_app_info_path);
+ if (ret < 0)
+ _E("Failed to remove appinfo children '%s': %s",
+ runtime_app_info_path, strerror(-ret));
+
+ return;
}
int proc_remove_app_list(const pid_t pid)
gslist_for_each_item(iter, proc_app_list) {
pai = (struct proc_app_info *)iter->data;
+ int ret;
+
if (!pai->main_pid)
continue;
if (pai->main_pid == pid) {
+ ret = proc_runtime_remove_app_info(pai);
+ if (ret < 0)
+ _E("Failed to remove appinfo '%s': %s",
+ pai->appid, strerror(-ret));
+
_remove_child_pids(pai, 0);
ppi = pai->program;
if (ppi) {
}
}
+static int proc_restore_runtime_app_info(const char *path)
+{
+ _cleanup_free_ char *appid = NULL, *pkgname = NULL;
+ struct proc_app_info *pai;
+ int oom_score_adj = 0, ret;
+
+ ret = proc_runtime_app_info_read_appid(path, &appid);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_pkgname(path, &pkgname);
+ if (ret < 0)
+ return ret;
+
+ pai = proc_create_app_list(appid, pkgname);
+ if (!pai)
+ return ret;
+
+ ret = proc_runtime_app_info_read_main_pid(path, (uint32_t *) &pai->main_pid);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_get_oom_score_adj(pai->main_pid, &oom_score_adj);
+ if (ret < 0) {
+ _I("pid %d is already terminated. remove it", pai->main_pid);
+ proc_app_list = g_slist_remove(proc_app_list, pai);
+ resourced_appinfo_put(pai->ai);
+ free(pai);
+ return ret;
+ }
+ pai->memory.oom_score_adj = oom_score_adj;
+
+ ret = proc_runtime_app_info_read_runtime_exclude(path, &pai->runtime_exclude);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_flags(path, &pai->flags);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_lru_state(path, &pai->lru_state);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_categories(path, &pai->categories);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_state(path, (int32_t *) &pai->state);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_type(path, (int32_t *) &pai->type);
+ if (ret < 0)
+ return ret;
+
+ ret = proc_runtime_app_info_read_procs(path, &pai->childs);
+ if (ret < 0 && ret != -ENOENT)
+ return ret;
+
+ pai->program = proc_add_program_list(pai->type, pai, pkgname);
+
+ _I("runtime appinfo restored: %s, %s", appid, pkgname);
+
+ return 0;
+}
+
+static void proc_restore_runtime_app_list(void)
+{
+ _cleanup_closedir_ DIR *dp = NULL;
+ struct dirent dentry;
+ struct dirent *dir;
+
+ dp = opendir(RUNTIME_APP_INFO_DIR);
+ if (!dp)
+ return;
+
+ while (!readdir_r(dp, &dentry, &dir) && dir != NULL) {
+ _cleanup_free_ char *path = NULL;
+ int ret;
+
+ if (dir->d_name[0] == '.')
+ continue;
+
+ if (dir->d_type != DT_DIR)
+ continue;
+
+ ret = asprintf(&path, RUNTIME_APP_INFO_DIR "/%s", dir->d_name);
+ if (ret < 0) {
+ _E("Failed to allocate memory");
+ return;
+ }
+
+ ret = proc_restore_runtime_app_info(path);
+ if (ret < 0)
+ _E("Failed to restore runtime appinfo '%s': %s",
+ dir->d_name, strerror(-ret));
+ }
+}
+
static int resourced_proc_init(void* data)
{
+ int ret = mkdir(RUNTIME_APP_INFO_DIR, S_IRWXU | S_IRGRP | S_IXGRP);
+ if (ret < 0 && errno != EEXIST) {
+ _E("Failed to create directory %s: %s", RUNTIME_APP_INFO_DIR, strerror(-ret));
+ return RESOURCED_ERROR_FAIL;
+ }
+
proc_exclude_init();
proc_module_init(data);
return RESOURCED_ERROR_NONE;
return RESOURCED_ERROR_NONE;
}
+static int resourced_proc_restore(void *data)
+{
+ proc_restore_runtime_app_list();
+ return RESOURCED_ERROR_NONE;
+}
+
int proc_get_freezer_status()
{
int ret = CGROUP_FREEZER_DISABLED;
.name = "PROC",
.init = resourced_proc_init,
.exit = resourced_proc_exit,
+ .restore = resourced_proc_restore,
};
MODULE_REGISTER(&proc_modules_ops)