lmkd: Support to send unsolicited message to clients

For now the only unsolicited message from lmkd is the process
kills on memory pressure.

Bug: 136036078
Test: atest ApplicationExitInfoTest

Change-Id: I503fd6a45ebab5276460b0ab978ebb2b8431dc0d
Signed-off-by: Jing Ji <jji@google.com>
This commit is contained in:
Jing Ji 2019-12-04 09:22:05 -08:00
parent a5845e7b60
commit 5c48096d8d
5 changed files with 250 additions and 204 deletions

View File

@ -88,3 +88,13 @@ properties:
ro.lmk.psi_complete_stall_ms: complete PSI stall threshold in milliseconds for ro.lmk.psi_complete_stall_ms: complete PSI stall threshold in milliseconds for
triggering critical memory notification. Default = triggering critical memory notification. Default =
700 700
lmkd will set the following Android properties according to current system
configurations:
sys.lmk.minfree_levels: minfree:oom_adj_score pairs, delimited by comma
sys.lmk.reportkills: whether or not it supports reporting process kills
to clients. Test app should check this property
before testing low memory kill notification.
Default will be unset.

View File

@ -27,11 +27,12 @@ __BEGIN_DECLS
* Supported LMKD commands * Supported LMKD commands
*/ */
enum lmk_cmd { enum lmk_cmd {
LMK_TARGET = 0, /* Associate minfree with oom_adj_score */ LMK_TARGET = 0, /* Associate minfree with oom_adj_score */
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */ LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
LMK_PROCREMOVE, /* Unregister a process */ LMK_PROCREMOVE, /* Unregister a process */
LMK_PROCPURGE, /* Purge all registered processes */ LMK_PROCPURGE, /* Purge all registered processes */
LMK_GETKILLCNT, /* Get number of kills */ LMK_GETKILLCNT, /* Get number of kills */
LMK_PROCKILL, /* Unsolicited msg to system_server on proc kills */
}; };
/* /*
@ -201,6 +202,17 @@ static inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int
return 2 * sizeof(int); return 2 * sizeof(int);
} }
/**
* Prepare LMK_PROCKILL unsolicited packet and return packet size in bytes.
* Warning: no checks performed, caller should ensure valid parameters.
*/
static inline size_t lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet, pid_t pid, uid_t uid) {
packet[0] = htonl(LMK_PROCKILL);
packet[1] = htonl(pid);
packet[2] = htonl(uid);
return 3 * sizeof(int);
}
__END_DECLS __END_DECLS
#endif /* _LMKD_H_ */ #endif /* _LMKD_H_ */

308
lmkd.c
View File

@ -200,7 +200,7 @@ static int psi_complete_stall_ms;
static int thrashing_limit_pct; static int thrashing_limit_pct;
static int thrashing_limit_decay_pct; static int thrashing_limit_decay_pct;
static bool use_psi_monitors = false; static bool use_psi_monitors = false;
static struct kernel_poll_info kpoll_info; static int kpoll_fd;
static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = { static struct psi_threshold psi_thresholds[VMPRESS_LEVEL_COUNT] = {
{ PSI_SOME, 70 }, /* 70ms out of 1sec for partial stall */ { PSI_SOME, 70 }, /* 70ms out of 1sec for partial stall */
{ PSI_SOME, 100 }, /* 100ms out of 1sec for partial stall */ { PSI_SOME, 100 }, /* 100ms out of 1sec for partial stall */
@ -638,6 +638,176 @@ static char *reread_file(struct reread_data *data) {
return buf; return buf;
} }
static bool claim_record(struct proc* procp, pid_t pid) {
if (procp->reg_pid == pid) {
/* Record already belongs to the registrant */
return true;
}
if (procp->reg_pid == 0) {
/* Old registrant is gone, claim the record */
procp->reg_pid = pid;
return true;
}
/* The record is owned by another registrant */
return false;
}
static void remove_claims(pid_t pid) {
int i;
for (i = 0; i < PIDHASH_SZ; i++) {
struct proc* procp = pidhash[i];
while (procp) {
if (procp->reg_pid == pid) {
procp->reg_pid = 0;
}
procp = procp->pidhash_next;
}
}
}
static void ctrl_data_close(int dsock_idx) {
struct epoll_event epev;
ALOGI("closing lmkd data connection");
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, data_sock[dsock_idx].sock, &epev) == -1) {
// Log a warning and keep going
ALOGW("epoll_ctl for data connection socket failed; errno=%d", errno);
}
maxevents--;
close(data_sock[dsock_idx].sock);
data_sock[dsock_idx].sock = -1;
/* Mark all records of the old registrant as unclaimed */
remove_claims(data_sock[dsock_idx].pid);
}
static ssize_t ctrl_data_read(int dsock_idx, char* buf, size_t bufsz, struct ucred* sender_cred) {
struct iovec iov = {buf, bufsz};
char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
NULL, 0, &iov, 1, control, sizeof(control), 0,
};
ssize_t ret;
ret = TEMP_FAILURE_RETRY(recvmsg(data_sock[dsock_idx].sock, &hdr, 0));
if (ret == -1) {
ALOGE("control data socket read failed; %s", strerror(errno));
return -1;
}
if (ret == 0) {
ALOGE("Got EOF on control data socket");
return -1;
}
struct ucred* cred = NULL;
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
while (cmsg != NULL) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
cred = (struct ucred*)CMSG_DATA(cmsg);
break;
}
cmsg = CMSG_NXTHDR(&hdr, cmsg);
}
if (cred == NULL) {
ALOGE("Failed to retrieve sender credentials");
/* Close the connection */
ctrl_data_close(dsock_idx);
return -1;
}
memcpy(sender_cred, cred, sizeof(struct ucred));
/* Store PID of the peer */
data_sock[dsock_idx].pid = cred->pid;
return ret;
}
static int ctrl_data_write(int dsock_idx, char* buf, size_t bufsz) {
int ret = 0;
ret = TEMP_FAILURE_RETRY(write(data_sock[dsock_idx].sock, buf, bufsz));
if (ret == -1) {
ALOGE("control data socket write failed; errno=%d", errno);
} else if (ret == 0) {
ALOGE("Got EOF on control data socket");
ret = -1;
}
return ret;
}
/*
* Write the pid/uid pair over the data socket, note: all active clients
* will receive this unsolicited notification.
*/
static void ctrl_data_write_lmk_kill_occurred(pid_t pid, uid_t uid) {
LMKD_CTRL_PACKET packet;
size_t len = lmkd_pack_set_prockills(packet, pid, uid);
for (int i = 0; i < MAX_DATA_CONN; i++) {
if (data_sock[i].sock >= 0) {
ctrl_data_write(i, (char*)packet, len);
}
}
}
static void poll_kernel(int poll_fd) {
if (poll_fd == -1) {
// not waiting
return;
}
while (1) {
char rd_buf[256];
int bytes_read = TEMP_FAILURE_RETRY(pread(poll_fd, (void*)rd_buf, sizeof(rd_buf), 0));
if (bytes_read <= 0) break;
rd_buf[bytes_read] = '\0';
int64_t pid;
int64_t uid;
int64_t group_leader_pid;
int64_t rss_in_pages;
struct memory_stat mem_st = {};
int16_t oom_score_adj;
int16_t min_score_adj;
int64_t starttime;
char* taskname = 0;
int fields_read =
sscanf(rd_buf,
"%" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
" %" SCNd16 " %" SCNd16 " %" SCNd64 "\n%m[^\n]",
&pid, &uid, &group_leader_pid, &mem_st.pgfault, &mem_st.pgmajfault,
&rss_in_pages, &oom_score_adj, &min_score_adj, &starttime, &taskname);
/* only the death of the group leader process is logged */
if (fields_read == 10 && group_leader_pid == pid) {
ctrl_data_write_lmk_kill_occurred((pid_t)pid, (uid_t)uid);
mem_st.process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
mem_st.rss_in_bytes = rss_in_pages * PAGE_SIZE;
stats_write_lmk_kill_occurred_pid(LMK_KILL_OCCURRED, uid, pid, oom_score_adj,
min_score_adj, 0, &mem_st);
}
free(taskname);
}
}
static bool init_poll_kernel() {
kpoll_fd = TEMP_FAILURE_RETRY(open("/proc/lowmemorykiller", O_RDONLY | O_NONBLOCK | O_CLOEXEC));
if (kpoll_fd < 0) {
ALOGE("kernel lmk event file could not be opened; errno=%d", errno);
return false;
}
return true;
}
static struct proc *pid_lookup(int pid) { static struct proc *pid_lookup(int pid) {
struct proc *procp; struct proc *procp;
@ -848,34 +1018,6 @@ static char *proc_get_name(int pid, char *buf, size_t buf_size) {
return buf; return buf;
} }
static bool claim_record(struct proc *procp, pid_t pid) {
if (procp->reg_pid == pid) {
/* Record already belongs to the registrant */
return true;
}
if (procp->reg_pid == 0) {
/* Old registrant is gone, claim the record */
procp->reg_pid = pid;
return true;
}
/* The record is owned by another registrant */
return false;
}
static void remove_claims(pid_t pid) {
int i;
for (i = 0; i < PIDHASH_SZ; i++) {
struct proc *procp = pidhash[i];
while (procp) {
if (procp->reg_pid == pid) {
procp->reg_pid = 0;
}
procp = procp->pidhash_next;
}
}
}
static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) { static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) {
struct proc *procp; struct proc *procp;
char path[LINE_MAX]; char path[LINE_MAX];
@ -920,8 +1062,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred
} }
if (use_inkernel_interface) { if (use_inkernel_interface) {
stats_store_taskname(params.pid, proc_get_name(params.pid, path, sizeof(path)), stats_store_taskname(params.pid, proc_get_name(params.pid, path, sizeof(path)));
kpoll_info.poll_fd);
return; return;
} }
@ -1015,7 +1156,15 @@ static void cmd_procremove(LMKD_CTRL_PACKET packet, struct ucred *cred) {
lmkd_pack_get_procremove(packet, &params); lmkd_pack_get_procremove(packet, &params);
if (use_inkernel_interface) { if (use_inkernel_interface) {
stats_remove_taskname(params.pid, kpoll_info.poll_fd); /*
* Perform an extra check before the pid is removed, after which it
* will be impossible for poll_kernel to get the taskname. poll_kernel()
* is potentially a long-running blocking function; however this method
* handles AMS requests but does not block AMS.
*/
poll_kernel(kpoll_fd);
stats_remove_taskname(params.pid);
return; return;
} }
@ -1198,81 +1347,6 @@ static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
} }
} }
static void ctrl_data_close(int dsock_idx) {
struct epoll_event epev;
ALOGI("closing lmkd data connection");
if (epoll_ctl(epollfd, EPOLL_CTL_DEL, data_sock[dsock_idx].sock, &epev) == -1) {
// Log a warning and keep going
ALOGW("epoll_ctl for data connection socket failed; errno=%d", errno);
}
maxevents--;
close(data_sock[dsock_idx].sock);
data_sock[dsock_idx].sock = -1;
/* Mark all records of the old registrant as unclaimed */
remove_claims(data_sock[dsock_idx].pid);
}
static ssize_t ctrl_data_read(int dsock_idx, char *buf, size_t bufsz, struct ucred *sender_cred) {
struct iovec iov = { buf, bufsz };
char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
NULL, 0, &iov, 1, control, sizeof(control), 0,
};
ssize_t ret;
ret = TEMP_FAILURE_RETRY(recvmsg(data_sock[dsock_idx].sock, &hdr, 0));
if (ret == -1) {
ALOGE("control data socket read failed; %s", strerror(errno));
return -1;
}
if (ret == 0) {
ALOGE("Got EOF on control data socket");
return -1;
}
struct ucred* cred = NULL;
struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
while (cmsg != NULL) {
if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
cred = (struct ucred*)CMSG_DATA(cmsg);
break;
}
cmsg = CMSG_NXTHDR(&hdr, cmsg);
}
if (cred == NULL) {
ALOGE("Failed to retrieve sender credentials");
/* Close the connection */
ctrl_data_close(dsock_idx);
return -1;
}
memcpy(sender_cred, cred, sizeof(struct ucred));
/* Store PID of the peer */
data_sock[dsock_idx].pid = cred->pid;
return ret;
}
static int ctrl_data_write(int dsock_idx, char *buf, size_t bufsz) {
int ret = 0;
ret = TEMP_FAILURE_RETRY(write(data_sock[dsock_idx].sock, buf, bufsz));
if (ret == -1) {
ALOGE("control data socket write failed; errno=%d", errno);
} else if (ret == 0) {
ALOGE("Got EOF on control data socket");
ret = -1;
}
return ret;
}
static void ctrl_command_handler(int dsock_idx) { static void ctrl_command_handler(int dsock_idx) {
LMKD_CTRL_PACKET packet; LMKD_CTRL_PACKET packet;
struct ucred cred; struct ucred cred;
@ -1327,6 +1401,10 @@ static void ctrl_command_handler(int dsock_idx) {
if (ctrl_data_write(dsock_idx, (char *)packet, len) != len) if (ctrl_data_write(dsock_idx, (char *)packet, len) != len)
return; return;
break; break;
case LMK_PROCKILL:
/* This command code is NOT expected at all */
ALOGE("Received unexpected command code %d", cmd);
break;
default: default:
ALOGE("Received unknown command code %d", cmd); ALOGE("Received unknown command code %d", cmd);
return; return;
@ -1946,6 +2024,8 @@ static int kill_one_process(struct proc* procp, int min_oom_score, int kill_reas
stats_write_lmk_kill_occurred(LMK_KILL_OCCURRED, uid, taskname, stats_write_lmk_kill_occurred(LMK_KILL_OCCURRED, uid, taskname,
procp->oomadj, min_oom_score, tasksize, mem_st); procp->oomadj, min_oom_score, tasksize, mem_st);
ctrl_data_write_lmk_kill_occurred((pid_t)pid, uid);
result = tasksize; result = tasksize;
out: out:
@ -2703,7 +2783,7 @@ err_open_mpfd:
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) {
kpoll_info.handler(kpoll_info.poll_fd); poll_kernel(kpoll_fd);
} }
static int init(void) { static int init(void) {
@ -2759,15 +2839,17 @@ static int init(void) {
if (use_inkernel_interface) { if (use_inkernel_interface) {
ALOGI("Using in-kernel low memory killer interface"); ALOGI("Using in-kernel low memory killer interface");
if (init_poll_kernel(&kpoll_info)) { if (init_poll_kernel()) {
epev.events = EPOLLIN; epev.events = EPOLLIN;
epev.data.ptr = (void*)&kernel_poll_hinfo; epev.data.ptr = (void*)&kernel_poll_hinfo;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, kpoll_info.poll_fd, &epev) != 0) { if (epoll_ctl(epollfd, EPOLL_CTL_ADD, kpoll_fd, &epev) != 0) {
ALOGE("epoll_ctl for lmk events failed (errno=%d)", errno); ALOGE("epoll_ctl for lmk events failed (errno=%d)", errno);
close(kpoll_info.poll_fd); close(kpoll_fd);
kpoll_info.poll_fd = -1; kpoll_fd = -1;
} else { } else {
maxevents++; maxevents++;
/* let the others know it does support reporting kills */
property_set("sys.lmk.reportkills", "1");
} }
} }
} else { } else {
@ -2787,6 +2869,8 @@ static int init(void) {
} else { } else {
ALOGI("Using vmpressure for memory pressure detection"); ALOGI("Using vmpressure for memory pressure detection");
} }
/* let the others know it does support reporting kills */
property_set("sys.lmk.reportkills", "1");
} }
for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) { for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {

View File

@ -181,9 +181,9 @@ stats_write_lmk_kill_occurred(int32_t code, int32_t uid, char const* process_nam
return write_to_logger(log_ctx, LOG_ID_STATS); return write_to_logger(log_ctx, LOG_ID_STATS);
} }
static int stats_write_lmk_kill_occurred_pid(int32_t code, int32_t uid, int pid, int stats_write_lmk_kill_occurred_pid(int32_t code, int32_t uid, int pid, int32_t oom_score,
int32_t oom_score, int32_t min_oom_score, int tasksize, int32_t min_oom_score, int tasksize,
struct memory_stat *mem_st) { struct memory_stat* mem_st) {
struct proc* proc = pid_lookup(pid); struct proc* proc = pid_lookup(pid);
if (!proc) return -EINVAL; if (!proc) return -EINVAL;
@ -290,65 +290,6 @@ struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t ui
return NULL; return NULL;
} }
static void poll_kernel(int poll_fd) {
if (poll_fd == -1) {
// not waiting
return;
}
while (1) {
char rd_buf[256];
int bytes_read =
TEMP_FAILURE_RETRY(pread(poll_fd, (void*)rd_buf, sizeof(rd_buf), 0));
if (bytes_read <= 0) break;
rd_buf[bytes_read] = '\0';
int64_t pid;
int64_t uid;
int64_t group_leader_pid;
int64_t rss_in_pages;
struct memory_stat mem_st = {};
int16_t oom_score_adj;
int16_t min_score_adj;
int64_t starttime;
char* taskname = 0;
int fields_read = sscanf(rd_buf,
"%" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64 " %" SCNd64
" %" SCNd64 " %" SCNd16 " %" SCNd16 " %" SCNd64 "\n%m[^\n]",
&pid, &uid, &group_leader_pid, &mem_st.pgfault,
&mem_st.pgmajfault, &rss_in_pages, &oom_score_adj,
&min_score_adj, &starttime, &taskname);
/* only the death of the group leader process is logged */
if (fields_read == 10 && group_leader_pid == pid) {
mem_st.process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
mem_st.rss_in_bytes = rss_in_pages * PAGE_SIZE;
stats_write_lmk_kill_occurred_pid(LMK_KILL_OCCURRED, uid, pid, oom_score_adj,
min_score_adj, 0, &mem_st);
}
free(taskname);
}
}
bool init_poll_kernel(struct kernel_poll_info *poll_info) {
if (!enable_stats_log) {
return false;
}
poll_info->poll_fd =
TEMP_FAILURE_RETRY(open("/proc/lowmemorykiller", O_RDONLY | O_NONBLOCK | O_CLOEXEC));
if (poll_info->poll_fd < 0) {
ALOGE("kernel lmk event file could not be opened; errno=%d", errno);
return false;
}
poll_info->handler = poll_kernel;
return true;
}
static void proc_insert(struct proc* procp) { static void proc_insert(struct proc* procp) {
if (!pidhash) { if (!pidhash) {
pidhash = calloc(PIDHASH_SZ, sizeof(*pidhash)); pidhash = calloc(PIDHASH_SZ, sizeof(*pidhash));
@ -359,19 +300,11 @@ static void proc_insert(struct proc* procp) {
pidhash[hval] = procp; pidhash[hval] = procp;
} }
void stats_remove_taskname(int pid, int poll_fd) { void stats_remove_taskname(int pid) {
if (!enable_stats_log || !pidhash) { if (!enable_stats_log || !pidhash) {
return; return;
} }
/*
* Perform an extra check before the pid is removed, after which it
* will be impossible for poll_kernel to get the taskname. poll_kernel()
* is potentially a long-running blocking function; however this method
* handles AMS requests but does not block AMS.
*/
poll_kernel(poll_fd);
int hval = pid_hashfn(pid); int hval = pid_hashfn(pid);
struct proc* procp; struct proc* procp;
struct proc* prevp; struct proc* prevp;
@ -391,7 +324,7 @@ void stats_remove_taskname(int pid, int poll_fd) {
free(procp); free(procp);
} }
void stats_store_taskname(int pid, const char* taskname, int poll_fd) { void stats_store_taskname(int pid, const char* taskname) {
if (!enable_stats_log) { if (!enable_stats_log) {
return; return;
} }
@ -401,7 +334,7 @@ void stats_store_taskname(int pid, const char* taskname, int poll_fd) {
if (strcmp(procp->taskname, taskname) == 0) { if (strcmp(procp->taskname, taskname) == 0) {
return; return;
} }
stats_remove_taskname(pid, poll_fd); stats_remove_taskname(pid);
} }
procp = malloc(sizeof(struct proc)); procp = malloc(sizeof(struct proc));
procp->pid = pid; procp->pid = pid;

View File

@ -22,6 +22,7 @@
#include <stats_event_list.h> #include <stats_event_list.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/types.h>
#include <cutils/properties.h> #include <cutils/properties.h>
@ -36,11 +37,6 @@ struct memory_stat {
int64_t process_start_time_ns; int64_t process_start_time_ns;
}; };
struct kernel_poll_info {
int poll_fd;
void (*handler)(int poll_fd);
};
/* /*
* These are defined in * These are defined in
* http://cs/android/frameworks/base/cmds/statsd/src/atoms.proto * http://cs/android/frameworks/base/cmds/statsd/src/atoms.proto
@ -84,12 +80,20 @@ stats_write_lmk_kill_occurred(int32_t code, int32_t uid,
char const* process_name, int32_t oom_score, int32_t min_oom_score, char const* process_name, int32_t oom_score, int32_t min_oom_score,
int tasksize, struct memory_stat *mem_st); int tasksize, struct memory_stat *mem_st);
/**
* Logs the event when LMKD kills a process to reduce memory pressure.
* Code: LMK_KILL_OCCURRED = 51
*/
int stats_write_lmk_kill_occurred_pid(int32_t code, int32_t uid, int pid, int32_t oom_score,
int32_t min_oom_score, int tasksize,
struct memory_stat* mem_st);
struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t uid); struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t uid);
/** /**
* Registers a process taskname by pid, while it is still alive. * Registers a process taskname by pid, while it is still alive.
*/ */
void stats_store_taskname(int pid, const char* taskname, int poll_fd); void stats_store_taskname(int pid, const char* taskname);
/** /**
* Unregister all process tasknames. * Unregister all process tasknames.
@ -99,9 +103,7 @@ void stats_purge_tasknames();
/** /**
* Unregister a process taskname, e.g. after it has been killed. * Unregister a process taskname, e.g. after it has been killed.
*/ */
void stats_remove_taskname(int pid, int poll_fd); void stats_remove_taskname(int pid);
bool init_poll_kernel(struct kernel_poll_info *poll_info);
#else /* LMKD_LOG_STATS */ #else /* LMKD_LOG_STATS */
@ -117,17 +119,22 @@ stats_write_lmk_kill_occurred(int32_t code __unused, int32_t uid __unused,
int32_t min_oom_score __unused, int tasksize __unused, int32_t min_oom_score __unused, int tasksize __unused,
struct memory_stat *mem_st __unused) { return -EINVAL; } struct memory_stat *mem_st __unused) { return -EINVAL; }
static inline int stats_write_lmk_kill_occurred_pid(int32_t code __unused, int32_t uid __unused,
int pid __unused, int32_t oom_score __unused,
int32_t min_oom_score __unused,
int tasksize __unused,
struct memory_stat* mem_st __unused) {
return -EINVAL;
}
static inline struct memory_stat *stats_read_memory_stat(bool per_app_memcg __unused, static inline struct memory_stat *stats_read_memory_stat(bool per_app_memcg __unused,
int pid __unused, uid_t uid __unused) { return NULL; } int pid __unused, uid_t uid __unused) { return NULL; }
static inline void stats_store_taskname(int pid __unused, const char* taskname __unused, static inline void stats_store_taskname(int pid __unused, const char* taskname __unused) {}
int poll_fd __unused) {}
static inline void stats_purge_tasknames() {} static inline void stats_purge_tasknames() {}
static inline void stats_remove_taskname(int pid __unused, int poll_fd __unused) {} static inline void stats_remove_taskname(int pid __unused) {}
static inline bool init_poll_kernel(struct kernel_poll_info *poll_info __unused) { return false; }
#endif /* LMKD_LOG_STATS */ #endif /* LMKD_LOG_STATS */