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> Merged-In: Ic60331f3368f5a7fdfe09ad7d47c7ccf0a497685 Change-Id: Ic60331f3368f5a7fdfe09ad7d47c7ccf0a497685
This commit is contained in:
parent
0eefbff7b9
commit
c4081918a7
|
|
@ -24,6 +24,7 @@ cc_binary {
|
|||
static_libs: [
|
||||
"libstatslogc",
|
||||
"libstatslog_lmkd",
|
||||
"liblmkd_utils",
|
||||
],
|
||||
local_include_dirs: ["include"],
|
||||
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);
|
||||
|
||||
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.
|
||||
* On success returns 0.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ enum lmk_cmd {
|
|||
LMK_GETKILLCNT, /* Get number of kills */
|
||||
LMK_SUBSCRIBE, /* Subscribe for asynchronous events */
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
||||
#endif /* _LMKD_H_ */
|
||||
|
|
|
|||
|
|
@ -53,6 +53,30 @@ int lmkd_unregister_proc(int sock, struct lmk_procremove *params) {
|
|||
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) {
|
||||
char buf[256];
|
||||
int tasks_file;
|
||||
|
|
|
|||
158
lmkd.cpp
158
lmkd.cpp
|
|
@ -42,6 +42,7 @@
|
|||
#include <cutils/properties.h>
|
||||
#include <cutils/sched_policy.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <liblmkd_utils.h>
|
||||
#include <lmkd.h>
|
||||
#include <log/log.h>
|
||||
#include <log/log_event_list.h>
|
||||
|
|
@ -142,6 +143,8 @@
|
|||
/* ro.lmk.psi_complete_stall_ms property defaults */
|
||||
#define DEF_COMPLETE_STALL 700
|
||||
|
||||
#define LMKD_REINIT_PROP "lmkd.reinit"
|
||||
|
||||
static inline int sys_pidfd_open(pid_t pid, unsigned int flags) {
|
||||
return syscall(__NR_pidfd_open, pid, flags);
|
||||
}
|
||||
|
|
@ -526,6 +529,10 @@ static uint32_t killcnt_total = 0;
|
|||
/* PAGE_SIZE / 1024 */
|
||||
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) {
|
||||
return max(min(value, high), low);
|
||||
}
|
||||
|
|
@ -1364,6 +1371,7 @@ static void ctrl_command_handler(int dsock_idx) {
|
|||
int nargs;
|
||||
int targets;
|
||||
int kill_cnt;
|
||||
int result;
|
||||
|
||||
len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE, &cred);
|
||||
if (len <= 0)
|
||||
|
|
@ -1419,6 +1427,29 @@ static void ctrl_command_handler(int dsock_idx) {
|
|||
/* This command code is NOT expected at all */
|
||||
ALOGE("Received unexpected command code %d", cmd);
|
||||
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:
|
||||
ALOGE("Received unknown command code %d", cmd);
|
||||
return;
|
||||
|
|
@ -1923,9 +1954,9 @@ static void stop_wait_for_proc_kill(bool finished) {
|
|||
|
||||
if (pidfd_supported) {
|
||||
/* 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);
|
||||
return;
|
||||
}
|
||||
maxevents--;
|
||||
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) {
|
||||
int fd = mpevfd[level];
|
||||
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unregister_psi_monitor(epollfd, fd) < 0) {
|
||||
ALOGE("Failed to unregister psi monitor for %s memory pressure; errno=%d",
|
||||
level_name[level], errno);
|
||||
}
|
||||
maxevents--;
|
||||
destroy_psi_monitor(fd);
|
||||
mpevfd[level] = -1;
|
||||
}
|
||||
|
|
@ -2794,11 +2830,60 @@ err_open_mpfd:
|
|||
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,
|
||||
struct polling_params *poll_params __unused) {
|
||||
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 struct event_handler_info kernel_poll_hinfo = { 0, kernel_event_handler };
|
||||
struct reread_data file_data = {
|
||||
|
|
@ -2866,22 +2951,9 @@ static int init(void) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
/* 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");
|
||||
if (!init_monitors()) {
|
||||
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 */
|
||||
property_set("sys.lmk.reportkills", "1");
|
||||
}
|
||||
|
|
@ -2965,7 +3037,7 @@ static void mainloop(void) {
|
|||
poll_params.update = POLLING_DO_NOT_CHANGE;
|
||||
|
||||
while (1) {
|
||||
struct epoll_event events[maxevents];
|
||||
struct epoll_event events[MAX_EPOLL_EVENTS];
|
||||
int nevents;
|
||||
int i;
|
||||
|
||||
|
|
@ -3042,11 +3114,41 @@ static void mainloop(void) {
|
|||
}
|
||||
}
|
||||
|
||||
int main(int argc __unused, char **argv __unused) {
|
||||
struct sched_param param = {
|
||||
.sched_priority = 1,
|
||||
};
|
||||
int issue_reinit() {
|
||||
LMKD_CTRL_PACKET packet;
|
||||
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 */
|
||||
level_oomadj[VMPRESS_LEVEL_LOW] =
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -3104,6 +3217,9 @@ int main(int argc __unused, char **argv __unused) {
|
|||
}
|
||||
|
||||
/* CAP_NICE required */
|
||||
struct sched_param param = {
|
||||
.sched_priority = 1,
|
||||
};
|
||||
if (sched_setscheduler(0, SCHED_FIFO, ¶m)) {
|
||||
ALOGW("set SCHED_FIFO failed %s", strerror(errno));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue