lmkd: Add property re-initialization support
Add --reinit command-line option to allow updating lmkd properties. For example to enable debug logging in the running lmkd process user should issue: setprop ro.lmk.debug true lmkd --reinit Bug: 155149944 Test: lmkd_unit_test after resetting lmkd properties Signed-off-by: Suren Baghdasaryan <surenb@google.com> Change-Id: Ic60331f3368f5a7fdfe09ad7d47c7ccf0a497685
This commit is contained in:
parent
03dccf35a1
commit
1d0ebeaa9c
|
|
@ -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"],
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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_ */
|
||||||
|
|
|
||||||
|
|
@ -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, ¶ms);
|
||||||
|
|
||||||
|
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
158
lmkd.cpp
|
|
@ -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);
|
||||||
|
|
@ -2709,10 +2740,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;
|
||||||
}
|
}
|
||||||
|
|
@ -2815,11 +2851,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 = {
|
||||||
|
|
@ -2887,22 +2972,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");
|
||||||
}
|
}
|
||||||
|
|
@ -2993,7 +3065,7 @@ static void mainloop(void) {
|
||||||
poll_params.paused_handler = NULL;
|
poll_params.paused_handler = NULL;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct epoll_event events[maxevents];
|
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||||
int nevents;
|
int nevents;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -3085,11 +3157,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);
|
||||||
|
|
@ -3126,6 +3228,17 @@ int main(int argc __unused, char **argv __unused) {
|
||||||
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));
|
||||||
swap_util_max = clamp(0, 100, property_get_int32("ro.lmk.swap_util_max", 100));
|
swap_util_max = clamp(0, 100, property_get_int32("ro.lmk.swap_util_max", 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
@ -3148,6 +3261,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, ¶m)) {
|
if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
|
||||||
ALOGW("set SCHED_FIFO failed %s", strerror(errno));
|
ALOGW("set SCHED_FIFO failed %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
lmkd.rc
3
lmkd.rc
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue