lmkd: Add property re-initialization support am: c4081918a7 am: a84a5e5801

Change-Id: Id3001f3ea024c9bf30ae919949c709f2776923e5
This commit is contained in:
Suren Baghdasaryan 2020-05-08 22:40:41 +00:00 committed by Automerger Merge Worker
commit f8ea710bef
6 changed files with 213 additions and 21 deletions

View File

@ -24,6 +24,7 @@ cc_binary {
static_libs: [ static_libs: [
"libstatslogc", "libstatslogc",
"libstatslog_lmkd", "libstatslog_lmkd",
"liblmkd_utils",
], ],
local_include_dirs: ["include"], local_include_dirs: ["include"],
cflags: ["-Werror", "-DLMKD_TRACE_KILLS"], cflags: ["-Werror", "-DLMKD_TRACE_KILLS"],

View File

@ -47,6 +47,20 @@ int lmkd_register_proc(int sock, struct lmk_procprio *params);
*/ */
int lmkd_unregister_proc(int sock, struct lmk_procremove *params); int lmkd_unregister_proc(int sock, struct lmk_procremove *params);
enum update_props_result {
UPDATE_PROPS_SUCCESS,
UPDATE_PROPS_FAIL,
UPDATE_PROPS_SEND_ERR,
UPDATE_PROPS_RECV_ERR,
UPDATE_PROPS_FORMAT_ERR,
};
/*
* Updates lmkd properties.
* In the case of ERR_SEND or ERR_RECV errno is set appropriately.
*/
enum update_props_result lmkd_update_props(int sock);
/* /*
* Creates memcg directory for given process. * Creates memcg directory for given process.
* On success returns 0. * On success returns 0.

View File

@ -34,6 +34,7 @@ enum lmk_cmd {
LMK_GETKILLCNT, /* Get number of kills */ LMK_GETKILLCNT, /* Get number of kills */
LMK_SUBSCRIBE, /* Subscribe for asynchronous events */ LMK_SUBSCRIBE, /* Subscribe for asynchronous events */
LMK_PROCKILL, /* Unsolicited msg to subscribed clients on proc kills */ LMK_PROCKILL, /* Unsolicited msg to subscribed clients on proc kills */
LMK_UPDATE_PROPS, /* Reinit properties */
}; };
/* /*
@ -244,6 +245,39 @@ static inline size_t lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet, pid_t pid,
return 3 * sizeof(int); return 3 * sizeof(int);
} }
/*
* Prepare LMK_UPDATE_PROPS packet and return packet size in bytes.
* Warning: no checks performed, caller should ensure valid parameters.
*/
static inline size_t lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet) {
packet[0] = htonl(LMK_UPDATE_PROPS);
return sizeof(int);
}
/*
* Prepare LMK_UPDATE_PROPS reply packet and return packet size in bytes.
* Warning: no checks performed, caller should ensure valid parameters.
*/
static inline size_t lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet, int result) {
packet[0] = htonl(LMK_UPDATE_PROPS);
packet[1] = htonl(result);
return 2 * sizeof(int);
}
/* LMK_PROCPRIO reply payload */
struct lmk_update_props_reply {
int result;
};
/*
* For LMK_UPDATE_PROPS reply payload.
* Warning: no checks performed, caller should ensure valid parameters.
*/
static inline void lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,
struct lmk_update_props_reply* params) {
params->result = ntohl(packet[1]);
}
__END_DECLS __END_DECLS
#endif /* _LMKD_H_ */ #endif /* _LMKD_H_ */

View File

@ -53,6 +53,30 @@ int lmkd_unregister_proc(int sock, struct lmk_procremove *params) {
return (ret < 0) ? -1 : 0; return (ret < 0) ? -1 : 0;
} }
enum update_props_result lmkd_update_props(int sock) {
LMKD_CTRL_PACKET packet;
size_t size;
size = lmkd_pack_set_update_props(packet);
if (TEMP_FAILURE_RETRY(write(sock, packet, size)) < 0) {
return UPDATE_PROPS_SEND_ERR;
}
size = TEMP_FAILURE_RETRY(read(sock, packet, CTRL_PACKET_MAX_SIZE));
if (size < 0) {
return UPDATE_PROPS_RECV_ERR;
}
if (size != 2 * sizeof(int) || lmkd_pack_get_cmd(packet) != LMK_UPDATE_PROPS) {
return UPDATE_PROPS_FORMAT_ERR;
}
struct lmk_update_props_reply params;
lmkd_pack_get_update_props_repl(packet, &params);
return params.result == 0 ? UPDATE_PROPS_SUCCESS : UPDATE_PROPS_FAIL;
}
int create_memcg(uid_t uid, pid_t pid) { int create_memcg(uid_t uid, pid_t pid) {
char buf[256]; char buf[256];
int tasks_file; int tasks_file;

158
lmkd.cpp
View File

@ -42,6 +42,7 @@
#include <cutils/properties.h> #include <cutils/properties.h>
#include <cutils/sched_policy.h> #include <cutils/sched_policy.h>
#include <cutils/sockets.h> #include <cutils/sockets.h>
#include <liblmkd_utils.h>
#include <lmkd.h> #include <lmkd.h>
#include <log/log.h> #include <log/log.h>
#include <log/log_event_list.h> #include <log/log_event_list.h>
@ -142,6 +143,8 @@
/* ro.lmk.psi_complete_stall_ms property defaults */ /* ro.lmk.psi_complete_stall_ms property defaults */
#define DEF_COMPLETE_STALL 700 #define DEF_COMPLETE_STALL 700
#define LMKD_REINIT_PROP "lmkd.reinit"
static inline int sys_pidfd_open(pid_t pid, unsigned int flags) { static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
return syscall(__NR_pidfd_open, pid, flags); return syscall(__NR_pidfd_open, pid, flags);
} }
@ -526,6 +529,10 @@ static uint32_t killcnt_total = 0;
/* PAGE_SIZE / 1024 */ /* PAGE_SIZE / 1024 */
static long page_k; static long page_k;
static void update_props();
static bool init_monitors();
static void destroy_monitors();
static int clamp(int low, int high, int value) { static int clamp(int low, int high, int value) {
return max(min(value, high), low); return max(min(value, high), low);
} }
@ -1364,6 +1371,7 @@ static void ctrl_command_handler(int dsock_idx) {
int nargs; int nargs;
int targets; int targets;
int kill_cnt; int kill_cnt;
int result;
len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE, &cred); len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE, &cred);
if (len <= 0) if (len <= 0)
@ -1419,6 +1427,29 @@ static void ctrl_command_handler(int dsock_idx) {
/* This command code is NOT expected at all */ /* This command code is NOT expected at all */
ALOGE("Received unexpected command code %d", cmd); ALOGE("Received unexpected command code %d", cmd);
break; break;
case LMK_UPDATE_PROPS:
if (nargs != 0)
goto wronglen;
update_props();
if (!use_inkernel_interface) {
/* Reinitialize monitors to apply new settings */
destroy_monitors();
result = init_monitors() ? 0 : -1;
} else {
result = 0;
}
len = lmkd_pack_set_update_props_repl(packet, result);
if (ctrl_data_write(dsock_idx, (char *)packet, len) != len) {
ALOGE("Failed to report operation results");
}
if (!result) {
ALOGI("Properties reinitilized");
} else {
/* New settings can't be supported, crash to be restarted */
ALOGE("New configuration is not supported. Exiting...");
exit(1);
}
break;
default: default:
ALOGE("Received unknown command code %d", cmd); ALOGE("Received unknown command code %d", cmd);
return; return;
@ -1923,9 +1954,9 @@ static void stop_wait_for_proc_kill(bool finished) {
if (pidfd_supported) { if (pidfd_supported) {
/* unregister fd */ /* unregister fd */
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, last_kill_pid_or_fd, &epev) != 0) { if (epoll_ctl(epollfd, EPOLL_CTL_DEL, last_kill_pid_or_fd, &epev)) {
// Log an error and keep going
ALOGE("epoll_ctl for last killed process failed; errno=%d", errno); ALOGE("epoll_ctl for last killed process failed; errno=%d", errno);
return;
} }
maxevents--; maxevents--;
close(last_kill_pid_or_fd); close(last_kill_pid_or_fd);
@ -2688,10 +2719,15 @@ static bool init_mp_psi(enum vmpressure_level level, bool use_new_strategy) {
static void destroy_mp_psi(enum vmpressure_level level) { static void destroy_mp_psi(enum vmpressure_level level) {
int fd = mpevfd[level]; int fd = mpevfd[level];
if (fd < 0) {
return;
}
if (unregister_psi_monitor(epollfd, fd) < 0) { if (unregister_psi_monitor(epollfd, fd) < 0) {
ALOGE("Failed to unregister psi monitor for %s memory pressure; errno=%d", ALOGE("Failed to unregister psi monitor for %s memory pressure; errno=%d",
level_name[level], errno); level_name[level], errno);
} }
maxevents--;
destroy_psi_monitor(fd); destroy_psi_monitor(fd);
mpevfd[level] = -1; mpevfd[level] = -1;
} }
@ -2794,11 +2830,60 @@ err_open_mpfd:
return false; return false;
} }
static void destroy_mp_common(enum vmpressure_level level) {
struct epoll_event epev;
int fd = mpevfd[level];
if (fd < 0) {
return;
}
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &epev)) {
// Log an error and keep going
ALOGE("epoll_ctl for level %s failed; errno=%d", level_name[level], errno);
}
maxevents--;
close(fd);
mpevfd[level] = -1;
}
static void kernel_event_handler(int data __unused, uint32_t events __unused, static void kernel_event_handler(int data __unused, uint32_t events __unused,
struct polling_params *poll_params __unused) { struct polling_params *poll_params __unused) {
poll_kernel(kpoll_fd); poll_kernel(kpoll_fd);
} }
static bool init_monitors() {
/* Try to use psi monitor first if kernel has it */
use_psi_monitors = property_get_bool("ro.lmk.use_psi", true) &&
init_psi_monitors();
/* Fall back to vmpressure */
if (!use_psi_monitors &&
(!init_mp_common(VMPRESS_LEVEL_LOW) ||
!init_mp_common(VMPRESS_LEVEL_MEDIUM) ||
!init_mp_common(VMPRESS_LEVEL_CRITICAL))) {
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
return false;
}
if (use_psi_monitors) {
ALOGI("Using psi monitors for memory pressure detection");
} else {
ALOGI("Using vmpressure for memory pressure detection");
}
return true;
}
static void destroy_monitors() {
if (use_psi_monitors) {
destroy_mp_psi(VMPRESS_LEVEL_CRITICAL);
destroy_mp_psi(VMPRESS_LEVEL_MEDIUM);
destroy_mp_psi(VMPRESS_LEVEL_LOW);
} else {
destroy_mp_common(VMPRESS_LEVEL_CRITICAL);
destroy_mp_common(VMPRESS_LEVEL_MEDIUM);
destroy_mp_common(VMPRESS_LEVEL_LOW);
}
}
static int init(void) { static int init(void) {
static struct event_handler_info kernel_poll_hinfo = { 0, kernel_event_handler }; static struct event_handler_info kernel_poll_hinfo = { 0, kernel_event_handler };
struct reread_data file_data = { struct reread_data file_data = {
@ -2866,22 +2951,9 @@ static int init(void) {
} }
} }
} else { } else {
/* Try to use psi monitor first if kernel has it */ if (!init_monitors()) {
use_psi_monitors = property_get_bool("ro.lmk.use_psi", true) &&
init_psi_monitors();
/* Fall back to vmpressure */
if (!use_psi_monitors &&
(!init_mp_common(VMPRESS_LEVEL_LOW) ||
!init_mp_common(VMPRESS_LEVEL_MEDIUM) ||
!init_mp_common(VMPRESS_LEVEL_CRITICAL))) {
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
return -1; return -1;
} }
if (use_psi_monitors) {
ALOGI("Using psi monitors for memory pressure detection");
} else {
ALOGI("Using vmpressure for memory pressure detection");
}
/* let the others know it does support reporting kills */ /* let the others know it does support reporting kills */
property_set("sys.lmk.reportkills", "1"); property_set("sys.lmk.reportkills", "1");
} }
@ -2965,7 +3037,7 @@ static void mainloop(void) {
poll_params.update = POLLING_DO_NOT_CHANGE; poll_params.update = POLLING_DO_NOT_CHANGE;
while (1) { while (1) {
struct epoll_event events[maxevents]; struct epoll_event events[MAX_EPOLL_EVENTS];
int nevents; int nevents;
int i; int i;
@ -3042,11 +3114,41 @@ static void mainloop(void) {
} }
} }
int main(int argc __unused, char **argv __unused) { int issue_reinit() {
struct sched_param param = { LMKD_CTRL_PACKET packet;
.sched_priority = 1, size_t size;
}; int sock;
sock = lmkd_connect();
if (sock < 0) {
ALOGE("failed to connect to lmkd: %s", strerror(errno));
return -1;
}
enum update_props_result res = lmkd_update_props(sock);
switch (res) {
case UPDATE_PROPS_SUCCESS:
ALOGI("lmkd updated properties successfully");
break;
case UPDATE_PROPS_SEND_ERR:
ALOGE("failed to send lmkd request: %s", strerror(errno));
break;
case UPDATE_PROPS_RECV_ERR:
ALOGE("failed to receive lmkd reply: %s", strerror(errno));
break;
case UPDATE_PROPS_FORMAT_ERR:
ALOGE("lmkd reply is invalid");
break;
case UPDATE_PROPS_FAIL:
ALOGE("lmkd failed to update its properties");
break;
}
close(sock);
return res == UPDATE_PROPS_SUCCESS ? 0 : -1;
}
static void update_props() {
/* By default disable low level vmpressure events */ /* By default disable low level vmpressure events */
level_oomadj[VMPRESS_LEVEL_LOW] = level_oomadj[VMPRESS_LEVEL_LOW] =
property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1); property_get_int32("ro.lmk.low", OOM_SCORE_ADJ_MAX + 1);
@ -3082,6 +3184,17 @@ int main(int argc __unused, char **argv __unused) {
low_ram_device ? DEF_THRASHING_LOWRAM : DEF_THRASHING)); low_ram_device ? DEF_THRASHING_LOWRAM : DEF_THRASHING));
thrashing_limit_decay_pct = clamp(0, 100, property_get_int32("ro.lmk.thrashing_limit_decay", thrashing_limit_decay_pct = clamp(0, 100, property_get_int32("ro.lmk.thrashing_limit_decay",
low_ram_device ? DEF_THRASHING_DECAY_LOWRAM : DEF_THRASHING_DECAY)); low_ram_device ? DEF_THRASHING_DECAY_LOWRAM : DEF_THRASHING_DECAY));
}
int main(int argc, char **argv) {
if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
if (property_set(LMKD_REINIT_PROP, "0")) {
ALOGE("Failed to reset " LMKD_REINIT_PROP " property");
}
return issue_reinit();
}
update_props();
ctx = create_android_logger(KILLINFO_LOG_TAG); ctx = create_android_logger(KILLINFO_LOG_TAG);
@ -3104,6 +3217,9 @@ int main(int argc __unused, char **argv __unused) {
} }
/* CAP_NICE required */ /* CAP_NICE required */
struct sched_param param = {
.sched_priority = 1,
};
if (sched_setscheduler(0, SCHED_FIFO, &param)) { if (sched_setscheduler(0, SCHED_FIFO, &param)) {
ALOGW("set SCHED_FIFO failed %s", strerror(errno)); ALOGW("set SCHED_FIFO failed %s", strerror(errno));
} }

View File

@ -6,3 +6,6 @@ service lmkd /system/bin/lmkd
critical critical
socket lmkd seqpacket+passcred 0660 system system socket lmkd seqpacket+passcred 0660 system system
writepid /dev/cpuset/system-background/tasks writepid /dev/cpuset/system-background/tasks
on property:lmkd.reinit=1
exec_background /system/bin/lmkd --reinit