Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 16b0946d authored by Colin Cross's avatar Colin Cross
Browse files

lmkd: kill multiple tasks

The task selected to die may be small, add its approximate size
to other_free and other_file and keep killing until all thresholds
are met.

Bug: 16236289
Change-Id: Iceeca4c63fec98cae2bf53e258f7707cea408b07
parent ce85d955
Loading
Loading
Loading
Loading
+88 −53
Original line number Diff line number Diff line
@@ -560,29 +560,57 @@ static struct proc *proc_adj_lru(int oomadj) {
    return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
}

static void mp_event(uint32_t events __unused) {
    int i;
    int ret;
    unsigned long long evcount;
    struct sysmeminfo mi;
    int other_free;
    int other_file;
    int minfree = 0;
    int min_score_adj = OOM_ADJUST_MAX + 1;
/* Kill one process specified by procp.  Returns the size of the process killed */
static int kill_one_process(struct proc *procp, int other_free, int other_file,
        int minfree, int min_score_adj, bool first)
{
    int pid = procp->pid;
    uid_t uid = procp->uid;
    char *taskname;
    int tasksize;
    int r;

    ret = read(mpevfd, &evcount, sizeof(evcount));
    if (ret < 0)
        ALOGE("Error reading memory pressure event fd; errno=%d",
              errno);
    taskname = proc_get_name(pid);
    if (!taskname) {
        pid_remove(pid);
        return -1;
    }

    if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
        return;
    tasksize = proc_get_size(pid);
    if (tasksize <= 0) {
        pid_remove(pid);
        return -1;
    }

    if (zoneinfo_parse(&mi) < 0)
        return;
    ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
          "   to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
          "   Free memory is %s%ldkB %s reserved",
          taskname, pid, uid, procp->oomadj, tasksize * page_k,
          first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
          first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
    r = kill(pid, SIGKILL);
    killProcessGroup(uid, pid, SIGKILL);
    pid_remove(pid);

    other_free = mi.nr_free_pages - mi.totalreserve_pages;
    other_file = mi.nr_file_pages - mi.nr_shmem;
    if (r) {
        ALOGE("kill(%d): errno=%d", procp->pid, errno);
        return -1;
    } else {
        return tasksize;
    }
}

/*
 * Find a process to kill based on the current (possibly estimated) free memory
 * and cached memory sizes.  Returns the size of the killed processes.
 */
static int find_and_kill_process(int other_free, int other_file, bool first)
{
    int i;
    int r;
    int min_score_adj = OOM_ADJUST_MAX + 1;
    int minfree = 0;
    int killed_size = 0;

    for (i = 0; i < lowmem_targets_size; i++) {
        minfree = lowmem_minfree[i];
@@ -593,7 +621,7 @@ static void mp_event(uint32_t events __unused) {
    }

    if (min_score_adj == OOM_ADJUST_MAX + 1)
        return;
        return 0;

    for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
        struct proc *procp;
@@ -602,43 +630,50 @@ static void mp_event(uint32_t events __unused) {
        procp = proc_adj_lru(i);

        if (procp) {
            int pid = procp->pid;
            uid_t uid = procp->uid;
            char *taskname;
            int tasksize;
            int r;

            taskname = proc_get_name(pid);
            if (!taskname) {
                pid_remove(pid);
            killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
            if (killed_size < 0) {
                goto retry;
            } else {
                return killed_size;
            }
        }
    }

            tasksize = proc_get_size(pid);
            if (tasksize < 0) {
                pid_remove(pid);
                goto retry;
    return 0;
}

            ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
                  "   to free %ldkB because cache %ldkB is below limit %ldkB for oom_adj %d\n"
                  "   Free memory is %ldkB %s reserved",
                  taskname, pid, uid, procp->oomadj, tasksize * page_k,
                  other_file * page_k, minfree * page_k, min_score_adj,
                  other_free * page_k, other_free >= 0 ? "above" : "below");
            r = kill(pid, SIGKILL);
            killProcessGroup(uid, pid, SIGKILL);
            pid_remove(pid);
static void mp_event(uint32_t events __unused) {
    int i;
    int ret;
    unsigned long long evcount;
    struct sysmeminfo mi;
    int other_free;
    int other_file;
    int killed_size;
    bool first = true;

            if (r) {
                ALOGE("kill(%d): errno=%d", procp->pid, errno);
                goto retry;
            } else {
                time(&kill_lasttime);
                break;
            }
        }
    ret = read(mpevfd, &evcount, sizeof(evcount));
    if (ret < 0)
        ALOGE("Error reading memory pressure event fd; errno=%d",
              errno);

    if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
        return;

    if (zoneinfo_parse(&mi) < 0)
        return;

    other_free = mi.nr_free_pages - mi.totalreserve_pages;
    other_file = mi.nr_file_pages - mi.nr_shmem;

    do {
        killed_size = find_and_kill_process(other_free, other_file, first);
        if (killed_size > 0) {
            first = false;
            other_free += killed_size;
            other_file += killed_size;
        }
    } while (killed_size > 0);
}

static int init_mp(char *levelstr, void *event_handler)