Loading healthd/HealthServiceCommon.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ using android::hardware::IPCThreadState; using android::hardware::configureRpcThreadpool; using android::hardware::handleTransportPoll; using android::hardware::setupTransportPolling; using android::hardware::health::V1_0::HealthInfo; using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo; using android::hardware::health::V2_0::IHealth; Loading @@ -35,21 +37,19 @@ using android::hardware::health::V2_0::implementation::Health; extern int healthd_main(void); static int gBinderFd = -1; static void binder_event(uint32_t /*epevents*/) { IPCThreadState::self()->handlePolledCommands(); if (gBinderFd >= 0) handleTransportPoll(gBinderFd); } void healthd_mode_service_2_0_init(struct healthd_config* config) { int binderFd; LOG(INFO) << LOG_TAG << " Hal is starting up..."; configureRpcThreadpool(1, false /* callerWillJoin */); IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->setupPolling(&binderFd); gBinderFd = setupTransportPolling(); if (binderFd >= 0) { if (healthd_register_event(binderFd, binder_event)) if (gBinderFd >= 0) { if (healthd_register_event(gBinderFd, binder_event)) LOG(ERROR) << LOG_TAG << ": Register for binder events failed"; } Loading init/property_service.cpp +17 −37 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ #include "init.h" #include "persistent_properties.h" #include "space_tokenizer.h" #include "util.h" using android::base::ReadFileToString; Loading @@ -69,6 +68,7 @@ using android::base::Timer; using android::base::Trim; using android::base::WriteStringToFile; using android::properties::BuildTrie; using android::properties::ParsePropertyInfoFile; using android::properties::PropertyInfoAreaFile; using android::properties::PropertyInfoEntry; Loading Loading @@ -350,9 +350,11 @@ class SocketConnection { ufds[0].events = POLLIN; ufds[0].revents = 0; while (*timeout_ms > 0) { Timer timer; auto start_time = std::chrono::steady_clock::now(); int nr = poll(ufds, 1, *timeout_ms); uint64_t millis = timer.duration().count(); auto now = std::chrono::steady_clock::now(); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); uint64_t millis = time_elapsed.count(); *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis; if (nr > 0) { Loading Loading @@ -726,22 +728,6 @@ static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, return 0; } Result<PropertyInfoEntry> ParsePropertyInfoLine(const std::string& line) { auto tokenizer = SpaceTokenizer(line); auto property = tokenizer.GetNext(); if (property.empty()) return Error() << "Did not find a property entry in '" << line << "'"; auto context = tokenizer.GetNext(); if (context.empty()) return Error() << "Did not find a context entry in '" << line << "'"; // It is not an error to not find these, as older files will not contain them. auto exact_match = tokenizer.GetNext(); auto schema = tokenizer.GetRemaining(); return {property, context, schema, exact_match == "exact"}; } bool LoadPropertyInfoFromFile(const std::string& filename, std::vector<PropertyInfoEntry>* property_infos) { auto file_contents = std::string(); Loading @@ -750,20 +736,14 @@ bool LoadPropertyInfoFromFile(const std::string& filename, return false; } for (const auto& line : Split(file_contents, "\n")) { auto trimmed_line = Trim(line); if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) { continue; auto errors = std::vector<std::string>{}; ParsePropertyInfoFile(file_contents, property_infos, &errors); // Individual parsing errors are reported but do not cause a failed boot, which is what // returning false would do here. for (const auto& error : errors) { LOG(ERROR) << "Could not read line from '" << filename << "': " << error; } auto property_info = ParsePropertyInfoLine(line); if (!property_info) { LOG(ERROR) << "Could not read line from '" << filename << "': " << property_info.error(); continue; } property_infos->emplace_back(*property_info); } return true; } Loading libnativeloader/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,8 @@ cc_library { "-fvisibility=hidden", ], export_include_dirs: ["include"], required: [ "llndk.libraries.txt", "vndksp.libraries.txt", ], } libsystem/include/system/graphics.h +5 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,11 @@ struct android_smpte2086_metadata { float minLuminance; }; struct android_cta861_3_metadata { float maxContentLightLevel; float maxFrameAverageLightLevel; }; #ifdef __cplusplus } #endif Loading lmkd/lmkd.c +84 −56 Original line number Diff line number Diff line Loading @@ -44,8 +44,6 @@ #define MEMCG_SYSFS_PATH "/dev/memcg/" #define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes" #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes" #define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium" #define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical" #define ZONEINFO_PATH "/proc/zoneinfo" #define LINE_MAX 128 Loading @@ -72,13 +70,22 @@ enum lmk_cmd { static int use_inkernel_interface = 1; static bool has_inkernel_module; /* memory pressure level medium event */ static int mpevfd[2]; #define CRITICAL_INDEX 1 #define MEDIUM_INDEX 0 /* memory pressure levels */ enum vmpressure_level { VMPRESS_LEVEL_LOW = 0, VMPRESS_LEVEL_MEDIUM, VMPRESS_LEVEL_CRITICAL, VMPRESS_LEVEL_COUNT }; static const char *level_name[] = { "low", "medium", "critical" }; static int medium_oomadj; static int critical_oomadj; static int level_oomadj[VMPRESS_LEVEL_COUNT]; static int mpevfd[VMPRESS_LEVEL_COUNT]; static bool debug_process_killing; static bool enable_pressure_upgrade; static int64_t upgrade_pressure; Loading @@ -90,8 +97,8 @@ static int ctrl_lfd; static int ctrl_dfd = -1; static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */ /* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */ #define MAX_EPOLL_EVENTS 4 /* 3 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */ #define MAX_EPOLL_EVENTS 5 static int epollfd; static int maxevents; Loading Loading @@ -226,7 +233,7 @@ static int pid_remove(int pid) { return 0; } static void writefilestring(char *path, char *s) { static void writefilestring(const char *path, char *s) { int fd = open(path, O_WRONLY | O_CLOEXEC); int len = strlen(s); int ret; Loading Loading @@ -587,7 +594,8 @@ static struct proc *proc_adj_lru(int oomadj) { } /* Kill one process specified by procp. Returns the size of the process killed */ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) { static int kill_one_process(struct proc* procp, int min_score_adj, enum vmpressure_level level) { int pid = procp->pid; uid_t uid = procp->uid; char *taskname; Loading @@ -606,12 +614,12 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti return -1; } r = kill(pid, SIGKILL); ALOGI( "Killing '%s' (%d), uid %d, adj %d\n" " to free %ldkB because system is under %s memory pressure oom_adj %d\n", taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium", min_score_adj); r = kill(pid, SIGKILL); taskname, pid, uid, procp->oomadj, tasksize * page_k, level_name[level], min_score_adj); pid_remove(pid); if (r) { Loading @@ -626,10 +634,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti * 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(bool is_critical) { static int find_and_kill_process(enum vmpressure_level level) { int i; int killed_size = 0; int min_score_adj = is_critical ? critical_oomadj : medium_oomadj; int min_score_adj = level_oomadj[level]; for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) { struct proc *procp; Loading @@ -638,7 +646,7 @@ retry: procp = proc_adj_lru(i); if (procp) { killed_size = kill_one_process(procp, min_score_adj, is_critical); killed_size = kill_one_process(procp, min_score_adj, level); if (killed_size < 0) { goto retry; } else { Loading Loading @@ -674,14 +682,23 @@ static int64_t get_memory_usage(const char* path) { return mem_usage; } static void mp_event_common(bool is_critical) { enum vmpressure_level upgrade_level(enum vmpressure_level level) { return (enum vmpressure_level)((level < VMPRESS_LEVEL_CRITICAL) ? level + 1 : level); } enum vmpressure_level downgrade_level(enum vmpressure_level level) { return (enum vmpressure_level)((level > VMPRESS_LEVEL_LOW) ? level - 1 : level); } static void mp_event_common(enum vmpressure_level level) { int ret; unsigned long long evcount; int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX; int64_t mem_usage, memsw_usage; int64_t mem_pressure; ret = read(mpevfd[index], &evcount, sizeof(evcount)); ret = read(mpevfd[level], &evcount, sizeof(evcount)); if (ret < 0) ALOGE("Error reading memory pressure event fd; errno=%d", errno); Loading @@ -689,18 +706,19 @@ static void mp_event_common(bool is_critical) { mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE); memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE); if (memsw_usage < 0 || mem_usage < 0) { find_and_kill_process(is_critical); return; goto do_kill; } // Calculate percent for swappinness. mem_pressure = (mem_usage * 100) / memsw_usage; if (enable_pressure_upgrade && !is_critical) { if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) { // We are swapping too much. if (mem_pressure < upgrade_pressure) { ALOGI("Event upgraded to critical."); is_critical = true; level = upgrade_level(level); if (debug_process_killing) { ALOGI("Event upgraded to %s", level_name[level]); } } } Loading @@ -708,41 +726,51 @@ static void mp_event_common(bool is_critical) { // kill any process, since enough memory is available. if (mem_pressure > downgrade_pressure) { if (debug_process_killing) { ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium"); ALOGI("Ignore %s memory pressure", level_name[level]); } return; } else if (is_critical && mem_pressure > upgrade_pressure) { } else if (level == VMPRESS_LEVEL_CRITICAL && mem_pressure > upgrade_pressure) { if (debug_process_killing) { ALOGI("Downgrade critical memory pressure"); } // Downgrade event to medium, since enough memory available. is_critical = false; // Downgrade event, since enough memory available. level = downgrade_level(level); } if (find_and_kill_process(is_critical) == 0) { do_kill: if (find_and_kill_process(level) == 0) { if (debug_process_killing) { ALOGI("Nothing to kill"); } } } static void mp_event(uint32_t events __unused) { mp_event_common(false); static void mp_event_low(uint32_t events __unused) { mp_event_common(VMPRESS_LEVEL_LOW); } static void mp_event_medium(uint32_t events __unused) { mp_event_common(VMPRESS_LEVEL_MEDIUM); } static void mp_event_critical(uint32_t events __unused) { mp_event_common(true); mp_event_common(VMPRESS_LEVEL_CRITICAL); } static int init_mp_common(char *levelstr, void *event_handler, bool is_critical) { static bool init_mp_common(void *event_handler, enum vmpressure_level level) { int mpfd; int evfd; int evctlfd; char buf[256]; struct epoll_event epev; int ret; int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX; const char *levelstr = level_name[level]; if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) { ALOGI("%s pressure events are disabled", levelstr); return true; } mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC); if (mpfd < 0) { Loading Loading @@ -783,8 +811,8 @@ static int init_mp_common(char *levelstr, void *event_handler, bool is_critical) goto err; } maxevents++; mpevfd[mpevfd_index] = evfd; return 0; mpevfd[level] = evfd; return true; err: close(evfd); Loading @@ -793,17 +821,7 @@ err_eventfd: err_open_evctlfd: close(mpfd); err_open_mpfd: return -1; } static int init_mp_medium() { return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false); } static int init_mp_critical() { return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true); return false; } static int init(void) { Loading Loading @@ -848,10 +866,13 @@ static int init(void) { if (use_inkernel_interface) { ALOGI("Using in-kernel low memory killer interface"); } else { ret = init_mp_medium(); ret |= init_mp_critical(); if (ret) if (!init_mp_common((void *)&mp_event_low, VMPRESS_LEVEL_LOW) || !init_mp_common((void *)&mp_event_medium, VMPRESS_LEVEL_MEDIUM) || !init_mp_common((void *)&mp_event_critical, VMPRESS_LEVEL_CRITICAL)) { ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer"); return -1; } } for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) { Loading Loading @@ -892,15 +913,22 @@ int main(int argc __unused, char **argv __unused) { .sched_priority = 1, }; medium_oomadj = property_get_int32("ro.lmk.medium", 800); critical_oomadj = property_get_int32("ro.lmk.critical", 0); /* By default disable low level vmpressure events */ level_oomadj[VMPRESS_LEVEL_LOW] = property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1); level_oomadj[VMPRESS_LEVEL_MEDIUM] = property_get_int32("ro.lmk.medium", 800); level_oomadj[VMPRESS_LEVEL_CRITICAL] = property_get_int32("ro.lmk.critical", 0); debug_process_killing = property_get_bool("ro.lmk.debug", false); enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false); upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50); downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60); is_go_device = property_get_bool("ro.config.low_ram", false); mlockall(MCL_FUTURE); if (mlockall(MCL_CURRENT | MCL_FUTURE)) ALOGW("mlockall failed: errno=%d", errno); sched_setscheduler(0, SCHED_FIFO, ¶m); if (!init()) mainloop(); Loading Loading
healthd/HealthServiceCommon.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -28,6 +28,8 @@ using android::hardware::IPCThreadState; using android::hardware::configureRpcThreadpool; using android::hardware::handleTransportPoll; using android::hardware::setupTransportPolling; using android::hardware::health::V1_0::HealthInfo; using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo; using android::hardware::health::V2_0::IHealth; Loading @@ -35,21 +37,19 @@ using android::hardware::health::V2_0::implementation::Health; extern int healthd_main(void); static int gBinderFd = -1; static void binder_event(uint32_t /*epevents*/) { IPCThreadState::self()->handlePolledCommands(); if (gBinderFd >= 0) handleTransportPoll(gBinderFd); } void healthd_mode_service_2_0_init(struct healthd_config* config) { int binderFd; LOG(INFO) << LOG_TAG << " Hal is starting up..."; configureRpcThreadpool(1, false /* callerWillJoin */); IPCThreadState::self()->disableBackgroundScheduling(true); IPCThreadState::self()->setupPolling(&binderFd); gBinderFd = setupTransportPolling(); if (binderFd >= 0) { if (healthd_register_event(binderFd, binder_event)) if (gBinderFd >= 0) { if (healthd_register_event(gBinderFd, binder_event)) LOG(ERROR) << LOG_TAG << ": Register for binder events failed"; } Loading
init/property_service.cpp +17 −37 Original line number Diff line number Diff line Loading @@ -58,7 +58,6 @@ #include "init.h" #include "persistent_properties.h" #include "space_tokenizer.h" #include "util.h" using android::base::ReadFileToString; Loading @@ -69,6 +68,7 @@ using android::base::Timer; using android::base::Trim; using android::base::WriteStringToFile; using android::properties::BuildTrie; using android::properties::ParsePropertyInfoFile; using android::properties::PropertyInfoAreaFile; using android::properties::PropertyInfoEntry; Loading Loading @@ -350,9 +350,11 @@ class SocketConnection { ufds[0].events = POLLIN; ufds[0].revents = 0; while (*timeout_ms > 0) { Timer timer; auto start_time = std::chrono::steady_clock::now(); int nr = poll(ufds, 1, *timeout_ms); uint64_t millis = timer.duration().count(); auto now = std::chrono::steady_clock::now(); auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time); uint64_t millis = time_elapsed.count(); *timeout_ms = (millis > *timeout_ms) ? 0 : *timeout_ms - millis; if (nr > 0) { Loading Loading @@ -726,22 +728,6 @@ static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, return 0; } Result<PropertyInfoEntry> ParsePropertyInfoLine(const std::string& line) { auto tokenizer = SpaceTokenizer(line); auto property = tokenizer.GetNext(); if (property.empty()) return Error() << "Did not find a property entry in '" << line << "'"; auto context = tokenizer.GetNext(); if (context.empty()) return Error() << "Did not find a context entry in '" << line << "'"; // It is not an error to not find these, as older files will not contain them. auto exact_match = tokenizer.GetNext(); auto schema = tokenizer.GetRemaining(); return {property, context, schema, exact_match == "exact"}; } bool LoadPropertyInfoFromFile(const std::string& filename, std::vector<PropertyInfoEntry>* property_infos) { auto file_contents = std::string(); Loading @@ -750,20 +736,14 @@ bool LoadPropertyInfoFromFile(const std::string& filename, return false; } for (const auto& line : Split(file_contents, "\n")) { auto trimmed_line = Trim(line); if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) { continue; auto errors = std::vector<std::string>{}; ParsePropertyInfoFile(file_contents, property_infos, &errors); // Individual parsing errors are reported but do not cause a failed boot, which is what // returning false would do here. for (const auto& error : errors) { LOG(ERROR) << "Could not read line from '" << filename << "': " << error; } auto property_info = ParsePropertyInfoLine(line); if (!property_info) { LOG(ERROR) << "Could not read line from '" << filename << "': " << property_info.error(); continue; } property_infos->emplace_back(*property_info); } return true; } Loading
libnativeloader/Android.bp +4 −0 Original line number Diff line number Diff line Loading @@ -19,4 +19,8 @@ cc_library { "-fvisibility=hidden", ], export_include_dirs: ["include"], required: [ "llndk.libraries.txt", "vndksp.libraries.txt", ], }
libsystem/include/system/graphics.h +5 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,11 @@ struct android_smpte2086_metadata { float minLuminance; }; struct android_cta861_3_metadata { float maxContentLightLevel; float maxFrameAverageLightLevel; }; #ifdef __cplusplus } #endif Loading
lmkd/lmkd.c +84 −56 Original line number Diff line number Diff line Loading @@ -44,8 +44,6 @@ #define MEMCG_SYSFS_PATH "/dev/memcg/" #define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes" #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes" #define MEMPRESSURE_WATCH_MEDIUM_LEVEL "medium" #define MEMPRESSURE_WATCH_CRITICAL_LEVEL "critical" #define ZONEINFO_PATH "/proc/zoneinfo" #define LINE_MAX 128 Loading @@ -72,13 +70,22 @@ enum lmk_cmd { static int use_inkernel_interface = 1; static bool has_inkernel_module; /* memory pressure level medium event */ static int mpevfd[2]; #define CRITICAL_INDEX 1 #define MEDIUM_INDEX 0 /* memory pressure levels */ enum vmpressure_level { VMPRESS_LEVEL_LOW = 0, VMPRESS_LEVEL_MEDIUM, VMPRESS_LEVEL_CRITICAL, VMPRESS_LEVEL_COUNT }; static const char *level_name[] = { "low", "medium", "critical" }; static int medium_oomadj; static int critical_oomadj; static int level_oomadj[VMPRESS_LEVEL_COUNT]; static int mpevfd[VMPRESS_LEVEL_COUNT]; static bool debug_process_killing; static bool enable_pressure_upgrade; static int64_t upgrade_pressure; Loading @@ -90,8 +97,8 @@ static int ctrl_lfd; static int ctrl_dfd = -1; static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */ /* 2 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */ #define MAX_EPOLL_EVENTS 4 /* 3 memory pressure levels, 1 ctrl listen socket, 1 ctrl data socket */ #define MAX_EPOLL_EVENTS 5 static int epollfd; static int maxevents; Loading Loading @@ -226,7 +233,7 @@ static int pid_remove(int pid) { return 0; } static void writefilestring(char *path, char *s) { static void writefilestring(const char *path, char *s) { int fd = open(path, O_WRONLY | O_CLOEXEC); int len = strlen(s); int ret; Loading Loading @@ -587,7 +594,8 @@ static struct proc *proc_adj_lru(int oomadj) { } /* Kill one process specified by procp. Returns the size of the process killed */ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_critical) { static int kill_one_process(struct proc* procp, int min_score_adj, enum vmpressure_level level) { int pid = procp->pid; uid_t uid = procp->uid; char *taskname; Loading @@ -606,12 +614,12 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti return -1; } r = kill(pid, SIGKILL); ALOGI( "Killing '%s' (%d), uid %d, adj %d\n" " to free %ldkB because system is under %s memory pressure oom_adj %d\n", taskname, pid, uid, procp->oomadj, tasksize * page_k, is_critical ? "critical" : "medium", min_score_adj); r = kill(pid, SIGKILL); taskname, pid, uid, procp->oomadj, tasksize * page_k, level_name[level], min_score_adj); pid_remove(pid); if (r) { Loading @@ -626,10 +634,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj, bool is_criti * 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(bool is_critical) { static int find_and_kill_process(enum vmpressure_level level) { int i; int killed_size = 0; int min_score_adj = is_critical ? critical_oomadj : medium_oomadj; int min_score_adj = level_oomadj[level]; for (i = OOM_SCORE_ADJ_MAX; i >= min_score_adj; i--) { struct proc *procp; Loading @@ -638,7 +646,7 @@ retry: procp = proc_adj_lru(i); if (procp) { killed_size = kill_one_process(procp, min_score_adj, is_critical); killed_size = kill_one_process(procp, min_score_adj, level); if (killed_size < 0) { goto retry; } else { Loading Loading @@ -674,14 +682,23 @@ static int64_t get_memory_usage(const char* path) { return mem_usage; } static void mp_event_common(bool is_critical) { enum vmpressure_level upgrade_level(enum vmpressure_level level) { return (enum vmpressure_level)((level < VMPRESS_LEVEL_CRITICAL) ? level + 1 : level); } enum vmpressure_level downgrade_level(enum vmpressure_level level) { return (enum vmpressure_level)((level > VMPRESS_LEVEL_LOW) ? level - 1 : level); } static void mp_event_common(enum vmpressure_level level) { int ret; unsigned long long evcount; int index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX; int64_t mem_usage, memsw_usage; int64_t mem_pressure; ret = read(mpevfd[index], &evcount, sizeof(evcount)); ret = read(mpevfd[level], &evcount, sizeof(evcount)); if (ret < 0) ALOGE("Error reading memory pressure event fd; errno=%d", errno); Loading @@ -689,18 +706,19 @@ static void mp_event_common(bool is_critical) { mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE); memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE); if (memsw_usage < 0 || mem_usage < 0) { find_and_kill_process(is_critical); return; goto do_kill; } // Calculate percent for swappinness. mem_pressure = (mem_usage * 100) / memsw_usage; if (enable_pressure_upgrade && !is_critical) { if (enable_pressure_upgrade && level != VMPRESS_LEVEL_CRITICAL) { // We are swapping too much. if (mem_pressure < upgrade_pressure) { ALOGI("Event upgraded to critical."); is_critical = true; level = upgrade_level(level); if (debug_process_killing) { ALOGI("Event upgraded to %s", level_name[level]); } } } Loading @@ -708,41 +726,51 @@ static void mp_event_common(bool is_critical) { // kill any process, since enough memory is available. if (mem_pressure > downgrade_pressure) { if (debug_process_killing) { ALOGI("Ignore %s memory pressure", is_critical ? "critical" : "medium"); ALOGI("Ignore %s memory pressure", level_name[level]); } return; } else if (is_critical && mem_pressure > upgrade_pressure) { } else if (level == VMPRESS_LEVEL_CRITICAL && mem_pressure > upgrade_pressure) { if (debug_process_killing) { ALOGI("Downgrade critical memory pressure"); } // Downgrade event to medium, since enough memory available. is_critical = false; // Downgrade event, since enough memory available. level = downgrade_level(level); } if (find_and_kill_process(is_critical) == 0) { do_kill: if (find_and_kill_process(level) == 0) { if (debug_process_killing) { ALOGI("Nothing to kill"); } } } static void mp_event(uint32_t events __unused) { mp_event_common(false); static void mp_event_low(uint32_t events __unused) { mp_event_common(VMPRESS_LEVEL_LOW); } static void mp_event_medium(uint32_t events __unused) { mp_event_common(VMPRESS_LEVEL_MEDIUM); } static void mp_event_critical(uint32_t events __unused) { mp_event_common(true); mp_event_common(VMPRESS_LEVEL_CRITICAL); } static int init_mp_common(char *levelstr, void *event_handler, bool is_critical) { static bool init_mp_common(void *event_handler, enum vmpressure_level level) { int mpfd; int evfd; int evctlfd; char buf[256]; struct epoll_event epev; int ret; int mpevfd_index = is_critical ? CRITICAL_INDEX : MEDIUM_INDEX; const char *levelstr = level_name[level]; if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) { ALOGI("%s pressure events are disabled", levelstr); return true; } mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY | O_CLOEXEC); if (mpfd < 0) { Loading Loading @@ -783,8 +811,8 @@ static int init_mp_common(char *levelstr, void *event_handler, bool is_critical) goto err; } maxevents++; mpevfd[mpevfd_index] = evfd; return 0; mpevfd[level] = evfd; return true; err: close(evfd); Loading @@ -793,17 +821,7 @@ err_eventfd: err_open_evctlfd: close(mpfd); err_open_mpfd: return -1; } static int init_mp_medium() { return init_mp_common(MEMPRESSURE_WATCH_MEDIUM_LEVEL, (void *)&mp_event, false); } static int init_mp_critical() { return init_mp_common(MEMPRESSURE_WATCH_CRITICAL_LEVEL, (void *)&mp_event_critical, true); return false; } static int init(void) { Loading Loading @@ -848,10 +866,13 @@ static int init(void) { if (use_inkernel_interface) { ALOGI("Using in-kernel low memory killer interface"); } else { ret = init_mp_medium(); ret |= init_mp_critical(); if (ret) if (!init_mp_common((void *)&mp_event_low, VMPRESS_LEVEL_LOW) || !init_mp_common((void *)&mp_event_medium, VMPRESS_LEVEL_MEDIUM) || !init_mp_common((void *)&mp_event_critical, VMPRESS_LEVEL_CRITICAL)) { ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer"); return -1; } } for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) { Loading Loading @@ -892,15 +913,22 @@ int main(int argc __unused, char **argv __unused) { .sched_priority = 1, }; medium_oomadj = property_get_int32("ro.lmk.medium", 800); critical_oomadj = property_get_int32("ro.lmk.critical", 0); /* By default disable low level vmpressure events */ level_oomadj[VMPRESS_LEVEL_LOW] = property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1); level_oomadj[VMPRESS_LEVEL_MEDIUM] = property_get_int32("ro.lmk.medium", 800); level_oomadj[VMPRESS_LEVEL_CRITICAL] = property_get_int32("ro.lmk.critical", 0); debug_process_killing = property_get_bool("ro.lmk.debug", false); enable_pressure_upgrade = property_get_bool("ro.lmk.critical_upgrade", false); upgrade_pressure = (int64_t)property_get_int32("ro.lmk.upgrade_pressure", 50); downgrade_pressure = (int64_t)property_get_int32("ro.lmk.downgrade_pressure", 60); is_go_device = property_get_bool("ro.config.low_ram", false); mlockall(MCL_FUTURE); if (mlockall(MCL_CURRENT | MCL_FUTURE)) ALOGW("mlockall failed: errno=%d", errno); sched_setscheduler(0, SCHED_FIFO, ¶m); if (!init()) mainloop(); Loading