Merge "init: increase thermal shutdown timeout to 3s" into pi-dev
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index e36f72b..ef1bf10 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -27,8 +27,8 @@
#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <sys/sysinfo.h>
+#include <sys/types.h>
#include <unistd.h>
#include <cutils/properties.h>
@@ -114,6 +114,7 @@
static bool kill_heaviest_task;
static unsigned long kill_timeout_ms;
static bool use_minfree_levels;
+static bool per_app_memcg;
/* data required to handle events */
struct event_handler_info {
@@ -523,6 +524,10 @@
return;
lmkd_pack_get_procremove(packet, ¶ms);
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
pid_remove(params.pid);
}
@@ -729,7 +734,7 @@
}
#ifdef LMKD_LOG_STATS
-static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) {
+static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) {
char key[LINE_MAX + 1];
int64_t value;
@@ -751,25 +756,62 @@
mem_st->swap_in_bytes = value;
}
-static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) {
- FILE *fp;
- char buf[PATH_MAX];
+static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) {
+ FILE* fp;
+ char buf[PATH_MAX];
- snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
+ snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid);
- fp = fopen(buf, "r");
+ fp = fopen(buf, "r");
- if (fp == NULL) {
- ALOGE("%s open failed: %s", buf, strerror(errno));
- return -1;
- }
+ if (fp == NULL) {
+ ALOGE("%s open failed: %s", buf, strerror(errno));
+ return -1;
+ }
- while (fgets(buf, PAGE_SIZE, fp) != NULL ) {
- memory_stat_parse_line(buf, mem_st);
- }
- fclose(fp);
+ while (fgets(buf, PAGE_SIZE, fp) != NULL) {
+ memory_stat_parse_line(buf, mem_st);
+ }
+ fclose(fp);
- return 0;
+ return 0;
+}
+
+static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
+ char path[PATH_MAX];
+ char buffer[PROC_STAT_BUFFER_SIZE];
+ int fd, ret;
+
+ snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
+ if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
+ ALOGE("%s open failed: %s", path, strerror(errno));
+ return -1;
+ }
+
+ ret = read(fd, buffer, sizeof(buffer));
+ if (ret < 0) {
+ ALOGE("%s read failed: %s", path, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+
+ // field 10 is pgfault
+ // field 12 is pgmajfault
+ // field 24 is rss_in_pages
+ int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0;
+ if (sscanf(buffer,
+ "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
+ "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
+ "%*d %*d %" SCNd64 "",
+ &pgfault, &pgmajfault, &rss_in_pages) != 3) {
+ return -1;
+ }
+ mem_st->pgfault = pgfault;
+ mem_st->pgmajfault = pgmajfault;
+ mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE);
+
+ return 0;
}
#endif
@@ -987,6 +1029,8 @@
return maxprocp;
}
+static int last_killed_pid = -1;
+
/* Kill one process specified by procp. Returns the size of the process killed */
static int kill_one_process(struct proc* procp) {
int pid = procp->pid;
@@ -994,6 +1038,7 @@
char *taskname;
int tasksize;
int r;
+ int result = -1;
#ifdef LMKD_LOG_STATS
struct memory_stat mem_st = {};
@@ -1002,46 +1047,59 @@
taskname = proc_get_name(pid);
if (!taskname) {
- pid_remove(pid);
- return -1;
+ goto out;
}
tasksize = proc_get_size(pid);
if (tasksize <= 0) {
- pid_remove(pid);
- return -1;
+ goto out;
}
#ifdef LMKD_LOG_STATS
if (enable_stats_log) {
- memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid);
+ if (per_app_memcg) {
+ memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid);
+ } else {
+ memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid);
+ }
}
#endif
TRACE_KILL_START(pid);
+ /* CAP_KILL required */
r = kill(pid, SIGKILL);
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
taskname, pid, uid, procp->oomadj, tasksize * page_k);
- pid_remove(pid);
TRACE_KILL_END();
+ last_killed_pid = pid;
+
if (r) {
ALOGE("kill(%d): errno=%d", pid, errno);
- return -1;
+ goto out;
} else {
#ifdef LMKD_LOG_STATS
if (memory_stat_parse_result == 0) {
stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
mem_st.cache_in_bytes, mem_st.swap_in_bytes);
+ } else if (enable_stats_log) {
+ stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
+ -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1);
}
#endif
- return tasksize;
+ result = tasksize;
}
- return tasksize;
+out:
+ /*
+ * WARNING: After pid_remove() procp is freed and can't be used!
+ * Therefore placed at the end of the function.
+ */
+ pid_remove(pid);
+ return result;
}
/*
@@ -1165,6 +1223,22 @@
(to->tv_usec - from->tv_usec) / 1000;
}
+static bool is_kill_pending(void) {
+ char buf[24];
+ if (last_killed_pid < 0) {
+ return false;
+ }
+
+ snprintf(buf, sizeof(buf), "/proc/%d/", last_killed_pid);
+ if (access(buf, F_OK) == 0) {
+ return true;
+ }
+
+ // reset last killed PID because there's nothing pending
+ last_killed_pid = -1;
+ return false;
+}
+
static void mp_event_common(int data, uint32_t events __unused) {
int ret;
unsigned long long evcount;
@@ -1206,7 +1280,11 @@
gettimeofday(&curr_tm, NULL);
if (kill_timeout_ms) {
- if (get_time_diff_ms(&last_kill_tm, &curr_tm) < kill_timeout_ms) {
+ // If we're within the timeout, see if there's pending reclaim work
+ // from the last killed process. If there is (as evidenced by
+ // /proc/<pid> continuing to exist), skip killing for now.
+ if ((get_time_diff_ms(&last_kill_tm, &curr_tm) < kill_timeout_ms) &&
+ (low_ram_device || is_kill_pending())) {
kill_skip_count++;
return;
}
@@ -1343,7 +1421,7 @@
min_score_adj = level_oomadj[level];
}
- pages_freed = find_and_kill_processes(min_score_adj, pages_to_free);
+ pages_freed = find_and_kill_processes(min_score_adj, 0);
if (pages_freed == 0) {
/* Rate limit kill reports when nothing was reclaimed */
@@ -1351,10 +1429,8 @@
report_skip_count++;
return;
}
- }
-
- if (pages_freed >= pages_to_free) {
- /* Reset kill time only if reclaimed enough memory */
+ } else {
+ /* If we killed anything, update the last killed timestamp. */
last_kill_tm = curr_tm;
}
@@ -1586,7 +1662,7 @@
(unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);
use_minfree_levels =
property_get_bool("ro.lmk.use_minfree_levels", false);
-
+ per_app_memcg = property_get_bool("ro.config.per_app_memcg", low_ram_device);
#ifdef LMKD_LOG_STATS
statslog_init(&log_ctx, &enable_stats_log);
#endif
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
index edebb19..8458480 100644
--- a/lmkd/statslog.h
+++ b/lmkd/statslog.h
@@ -67,6 +67,9 @@
};
#define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat"
+#define PROC_STAT_FILE_PATH "/proc/%d/stat"
+#define PROC_STAT_BUFFER_SIZE 1024
+#define BYTES_IN_KILOBYTE 1024
/**
* Logs the change in LMKD state which is used as start/stop boundaries for logging