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

Commit 26a7d648 authored by android-build-team Robot's avatar android-build-team Robot
Browse files

Snap for 4725392 from 7cb8aade to pi-release

Change-Id: I41683ad62b26109d9aa5eee925934092f6347d34
parents fa450920 7cb8aade
Loading
Loading
Loading
Loading
+23 −7
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/log.h>
#include <cutils/android_reboot.h>
@@ -957,14 +958,28 @@ void SetSystemBootReason() {
  SetProperty(system_reboot_reason_property, system_boot_reason);
}

// Gets the boot time offset. This is useful when Android is running in a
// container, because the boot_clock is not reset when Android reboots.
std::chrono::nanoseconds GetBootTimeOffset() {
  static const int64_t boottime_offset =
      android::base::GetIntProperty<int64_t>("ro.boot.boottime_offset", 0);
  return std::chrono::nanoseconds(boottime_offset);
}

// Returns the current uptime, accounting for any offset in the CLOCK_BOOTTIME
// clock.
android::base::boot_clock::duration GetUptime() {
  return android::base::boot_clock::now().time_since_epoch() - GetBootTimeOffset();
}

// Records several metrics related to the time it takes to boot the device,
// including disambiguating boot time on encrypted or non-encrypted devices.
void RecordBootComplete() {
  BootEventRecordStore boot_event_store;
  BootEventRecordStore::BootEventRecord record;

  auto time_since_epoch = android::base::boot_clock::now().time_since_epoch();
  auto uptime = std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch);
  auto uptime_ns = GetUptime();
  auto uptime_s = std::chrono::duration_cast<std::chrono::seconds>(uptime_ns);
  time_t current_time_utc = time(nullptr);
  time_t time_since_last_boot = 0;

@@ -990,19 +1005,20 @@ void RecordBootComplete() {
    // Log the amount of time elapsed until the device is decrypted, which
    // includes the variable amount of time the user takes to enter the
    // decryption password.
    boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime.count());
    boot_event_store.AddBootEventWithValue("boot_decryption_complete", uptime_s.count());

    // Subtract the decryption time to normalize the boot cycle timing.
    std::chrono::seconds boot_complete = std::chrono::seconds(uptime.count() - record.second);
    std::chrono::seconds boot_complete = std::chrono::seconds(uptime_s.count() - record.second);
    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_post_decrypt",
                                           boot_complete.count());
  } else {
    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption", uptime.count());
    boot_event_store.AddBootEventWithValue(boot_complete_prefix + "_no_encryption",
                                           uptime_s.count());
  }

  // Record the total time from device startup to boot complete, regardless of
  // encryption state.
  boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime.count());
  boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime_s.count());

  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
@@ -1012,7 +1028,7 @@ void RecordBootComplete() {
  int32_t bootloader_boot_duration = GetBootloaderTime(bootloader_timings);
  RecordBootloaderTimings(&boot_event_store, bootloader_timings);

  auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_since_epoch);
  auto uptime_ms = std::chrono::duration_cast<std::chrono::milliseconds>(uptime_ns);
  auto absolute_boot_time = GetAbsoluteBootTime(bootloader_timings, uptime_ms);
  RecordAbsoluteBootTime(&boot_event_store, absolute_boot_time);

lmkd/README.md

0 → 100644
+60 −0
Original line number Diff line number Diff line
Android Low Memory Killer Daemon
================================


Introduction
------------

Android Low Memory Killer Daemon (lmkd) is a process monitoring memory
state of a running Android system and reacting to high memory pressure
by killing the least essential process(es) to keep system performing
at acceptable levels.


Background
----------

Historically on Android systems memory monitoring and killing of
non-essential processes was handled by a kernel lowmemorykiller driver.
Since Linux Kernel 4.12 the lowmemorykiller driver has been removed and
instead userspace lmkd daemon performs these tasks.


Android Properties
------------------

lmkd can be configured on a particular system using the following Android
properties:

  ro.config.low_ram:         choose between low-memory vs high-performance
                             device. Default = false.

  ro.lmk.low:                min oom_adj score for processes eligible to be
                             killed at low vmpressure level. Default = 1001
                             (disabled)

  ro.lmk.medium:             min oom_adj score for processes eligible to be
                             killed at medium vmpressure level. Default = 800
                             (non-essential processes)

  ro.lmk.critical:           min oom_adj score for processes eligible to be
                             killed at critical vmpressure level. Default = 0
                             (all processes)

  ro.lmk.critical_upgrade:   enables upgrade to critical level. Default = false

  ro.lmk.upgrade_pressure:   max mem_pressure at which level will be upgraded
                             because system is swapping too much. Default = 100
                             (disabled)

  ro.lmk.downgrade_pressure: min mem_pressure at which vmpressure event will
                             be ignored because enough free memory is still
                             available. Default = 100 (disabled)

  ro.lmk.kill_heaviest_task: kill heaviest eligible task (best decision) vs.
                             any eligible task (fast decision). Default = false

  ro.lmk.kill_timeout_ms:    duration in ms after a kill when no additional
                             kill will be done, Default = 0 (disabled)

  ro.lmk.debug:              enable lmkd debug logs, Default = false
+79 −23
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ static bool debug_process_killing;
static bool enable_pressure_upgrade;
static int64_t upgrade_pressure;
static int64_t downgrade_pressure;
static bool is_go_device;
static bool low_ram_device;
static bool kill_heaviest_task;
static unsigned long kill_timeout_ms;

@@ -171,6 +171,11 @@ struct proc {
    struct proc *pidhash_next;
};

struct reread_data {
    const char* const filename;
    int fd;
};

#ifdef LMKD_LOG_STATS
static bool enable_stats_log;
static android_log_context log_ctx;
@@ -186,12 +191,27 @@ static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
/* PAGE_SIZE / 1024 */
static long page_k;

static bool parse_int64(const char* str, int64_t* ret) {
    char* endptr;
    long long val = strtoll(str, &endptr, 10);
    if (str == endptr || val > INT64_MAX) {
        return false;
    }
    *ret = (int64_t)val;
    return true;
}

/*
 * Read file content from the beginning up to max_len bytes or EOF
 * whichever happens first.
 */
static ssize_t read_all(int fd, char *buf, size_t max_len)
{
    ssize_t ret = 0;
    off_t offset = 0;

    while (max_len > 0) {
        ssize_t r = read(fd, buf, max_len);
        ssize_t r = TEMP_FAILURE_RETRY(pread(fd, buf, max_len, offset));
        if (r == 0) {
            break;
        }
@@ -200,12 +220,44 @@ static ssize_t read_all(int fd, char *buf, size_t max_len)
        }
        ret += r;
        buf += r;
        offset += r;
        max_len -= r;
    }

    return ret;
}

/*
 * Read a new or already opened file from the beginning.
 * If the file has not been opened yet data->fd should be set to -1.
 * To be used with files which are read often and possibly during high
 * memory pressure to minimize file opening which by itself requires kernel
 * memory allocation and might result in a stall on memory stressed system.
 */
static int reread_file(struct reread_data *data, char *buf, size_t buf_size) {
    ssize_t size;

    if (data->fd == -1) {
        data->fd = open(data->filename, O_RDONLY | O_CLOEXEC);
        if (data->fd == -1) {
            ALOGE("%s open: %s", data->filename, strerror(errno));
            return -1;
        }
    }

    size = read_all(data->fd, buf, buf_size - 1);
    if (size < 0) {
        ALOGE("%s read: %s", data->filename, strerror(errno));
        close(data->fd);
        data->fd = -1;
        return -1;
    }
    ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large");
    buf[size] = 0;

    return 0;
}

static struct proc *pid_lookup(int pid) {
    struct proc *procp;

@@ -442,7 +494,7 @@ static void ctrl_data_close(int dsock_idx) {
static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) {
    int ret = 0;

    ret = read(data_sock[dsock_idx].sock, buf, bufsz);
    ret = TEMP_FAILURE_RETRY(read(data_sock[dsock_idx].sock, buf, bufsz));

    if (ret == -1) {
        ALOGE("control data socket read failed; errno=%d", errno);
@@ -771,10 +823,8 @@ static int find_and_kill_processes(enum vmpressure_level level,
        struct proc *procp;

        while (true) {
            if (is_go_device)
                procp = proc_adj_lru(i);
            else
                procp = proc_get_heaviest(i);
            procp = kill_heaviest_task ?
                proc_get_heaviest(i) : proc_adj_lru(i);

            if (!procp)
                break;
@@ -805,23 +855,19 @@ static int find_and_kill_processes(enum vmpressure_level level,
    return pages_freed;
}

static int64_t get_memory_usage(const char* path) {
static int64_t get_memory_usage(struct reread_data *file_data) {
    int ret;
    int64_t mem_usage;
    char buf[32];
    int fd = open(path, O_RDONLY | O_CLOEXEC);
    if (fd == -1) {
        ALOGE("%s open: errno=%d", path, errno);

    if (reread_file(file_data, buf, sizeof(buf)) < 0) {
        return -1;
    }

    ret = read_all(fd, buf, sizeof(buf) - 1);
    close(fd);
    if (ret < 0) {
        ALOGE("%s error: errno=%d", path, errno);
    if (!parse_int64(buf, &mem_usage)) {
        ALOGE("%s parse error", file_data->filename);
        return -1;
    }
    sscanf(buf, "%" SCNd64, &mem_usage);
    if (mem_usage == 0) {
        ALOGE("No memory!");
        return -1;
@@ -881,6 +927,14 @@ static void mp_event_common(int data, uint32_t events __unused) {
    static struct timeval last_report_tm;
    static unsigned long skip_count = 0;
    enum vmpressure_level level = (enum vmpressure_level)data;
    static struct reread_data mem_usage_file_data = {
        .filename = MEMCG_MEMORY_USAGE,
        .fd = -1,
    };
    static struct reread_data memsw_usage_file_data = {
        .filename = MEMCG_MEMORYSW_USAGE,
        .fd = -1,
    };

    /*
     * Check all event counters from low to critical
@@ -889,7 +943,8 @@ static void mp_event_common(int data, uint32_t events __unused) {
     */
    for (lvl = VMPRESS_LEVEL_LOW; lvl < VMPRESS_LEVEL_COUNT; lvl++) {
        if (mpevfd[lvl] != -1 &&
            read(mpevfd[lvl], &evcount, sizeof(evcount)) > 0 &&
            TEMP_FAILURE_RETRY(read(mpevfd[lvl],
                               &evcount, sizeof(evcount))) > 0 &&
            evcount > 0 && lvl > level) {
            level = lvl;
        }
@@ -926,9 +981,10 @@ static void mp_event_common(int data, uint32_t events __unused) {
        return;
    }

    mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE);
    memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE);
    if (memsw_usage < 0 || mem_usage < 0) {
    if ((mem_usage = get_memory_usage(&mem_usage_file_data)) < 0) {
        goto do_kill;
    }
    if ((memsw_usage = get_memory_usage(&memsw_usage_file_data)) < 0) {
        goto do_kill;
    }

@@ -962,7 +1018,7 @@ static void mp_event_common(int data, uint32_t events __unused) {
    }

do_kill:
    if (is_go_device) {
    if (low_ram_device) {
        /* For Go devices kill only one task */
        if (find_and_kill_processes(level, 0) == 0) {
            if (debug_process_killing) {
@@ -1198,8 +1254,8 @@ int main(int argc __unused, char **argv __unused) {
    downgrade_pressure =
        (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 100);
    kill_heaviest_task =
        property_get_bool("ro.lmk.kill_heaviest_task", true);
    is_go_device = property_get_bool("ro.config.low_ram", false);
        property_get_bool("ro.lmk.kill_heaviest_task", false);
    low_ram_device = property_get_bool("ro.config.low_ram", false);
    kill_timeout_ms =
        (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0);