lmkd: Support to send unsolicited message to clients
am: 5c48096d8d
Change-Id: Idf8184718f6e5a1ed13c1ce3476df81a59335d7d
This commit is contained in:
commit
3123c4746c
10
README.md
10
README.md
|
|
@ -88,3 +88,13 @@ properties:
|
|||
ro.lmk.psi_complete_stall_ms: complete PSI stall threshold in milliseconds for
|
||||
triggering critical memory notification. Default =
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -27,11 +27,12 @@ __BEGIN_DECLS
|
|||
* Supported LMKD commands
|
||||
*/
|
||||
enum lmk_cmd {
|
||||
LMK_TARGET = 0, /* Associate minfree with oom_adj_score */
|
||||
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
|
||||
LMK_PROCREMOVE, /* Unregister a process */
|
||||
LMK_PROCPURGE, /* Purge all registered processes */
|
||||
LMK_GETKILLCNT, /* Get number of kills */
|
||||
LMK_TARGET = 0, /* Associate minfree with oom_adj_score */
|
||||
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
|
||||
LMK_PROCREMOVE, /* Unregister a process */
|
||||
LMK_PROCPURGE, /* Purge all registered processes */
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
#endif /* _LMKD_H_ */
|
||||
|
|
|
|||
308
lmkd.c
308
lmkd.c
|
|
@ -200,7 +200,7 @@ static int psi_complete_stall_ms;
|
|||
static int thrashing_limit_pct;
|
||||
static int thrashing_limit_decay_pct;
|
||||
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] = {
|
||||
{ PSI_SOME, 70 }, /* 70ms 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
struct proc *procp;
|
||||
|
||||
|
|
@ -848,34 +1018,6 @@ static char *proc_get_name(int pid, char *buf, size_t buf_size) {
|
|||
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) {
|
||||
struct proc *procp;
|
||||
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) {
|
||||
stats_store_taskname(params.pid, proc_get_name(params.pid, path, sizeof(path)),
|
||||
kpoll_info.poll_fd);
|
||||
stats_store_taskname(params.pid, proc_get_name(params.pid, path, sizeof(path)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1015,7 +1156,15 @@ static void cmd_procremove(LMKD_CTRL_PACKET packet, struct ucred *cred) {
|
|||
lmkd_pack_get_procremove(packet, ¶ms);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -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) {
|
||||
LMKD_CTRL_PACKET packet;
|
||||
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)
|
||||
return;
|
||||
break;
|
||||
case LMK_PROCKILL:
|
||||
/* This command code is NOT expected at all */
|
||||
ALOGE("Received unexpected command code %d", cmd);
|
||||
break;
|
||||
default:
|
||||
ALOGE("Received unknown command code %d", cmd);
|
||||
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,
|
||||
procp->oomadj, min_oom_score, tasksize, mem_st);
|
||||
|
||||
ctrl_data_write_lmk_kill_occurred((pid_t)pid, uid);
|
||||
|
||||
result = tasksize;
|
||||
|
||||
out:
|
||||
|
|
@ -2703,7 +2783,7 @@ err_open_mpfd:
|
|||
|
||||
static void kernel_event_handler(int data __unused, uint32_t events __unused,
|
||||
struct polling_params *poll_params __unused) {
|
||||
kpoll_info.handler(kpoll_info.poll_fd);
|
||||
poll_kernel(kpoll_fd);
|
||||
}
|
||||
|
||||
static int init(void) {
|
||||
|
|
@ -2759,15 +2839,17 @@ static int init(void) {
|
|||
|
||||
if (use_inkernel_interface) {
|
||||
ALOGI("Using in-kernel low memory killer interface");
|
||||
if (init_poll_kernel(&kpoll_info)) {
|
||||
if (init_poll_kernel()) {
|
||||
epev.events = EPOLLIN;
|
||||
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);
|
||||
close(kpoll_info.poll_fd);
|
||||
kpoll_info.poll_fd = -1;
|
||||
close(kpoll_fd);
|
||||
kpoll_fd = -1;
|
||||
} else {
|
||||
maxevents++;
|
||||
/* let the others know it does support reporting kills */
|
||||
property_set("sys.lmk.reportkills", "1");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2787,6 +2869,8 @@ static int init(void) {
|
|||
} else {
|
||||
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++) {
|
||||
|
|
|
|||
79
statslog.c
79
statslog.c
|
|
@ -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);
|
||||
}
|
||||
|
||||
static 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) {
|
||||
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 proc* proc = pid_lookup(pid);
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (!pidhash) {
|
||||
pidhash = calloc(PIDHASH_SZ, sizeof(*pidhash));
|
||||
|
|
@ -359,19 +300,11 @@ static void proc_insert(struct proc* procp) {
|
|||
pidhash[hval] = procp;
|
||||
}
|
||||
|
||||
void stats_remove_taskname(int pid, int poll_fd) {
|
||||
void stats_remove_taskname(int pid) {
|
||||
if (!enable_stats_log || !pidhash) {
|
||||
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);
|
||||
struct proc* procp;
|
||||
struct proc* prevp;
|
||||
|
|
@ -391,7 +324,7 @@ void stats_remove_taskname(int pid, int poll_fd) {
|
|||
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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -401,7 +334,7 @@ void stats_store_taskname(int pid, const char* taskname, int poll_fd) {
|
|||
if (strcmp(procp->taskname, taskname) == 0) {
|
||||
return;
|
||||
}
|
||||
stats_remove_taskname(pid, poll_fd);
|
||||
stats_remove_taskname(pid);
|
||||
}
|
||||
procp = malloc(sizeof(struct proc));
|
||||
procp->pid = pid;
|
||||
|
|
|
|||
35
statslog.h
35
statslog.h
|
|
@ -22,6 +22,7 @@
|
|||
#include <stats_event_list.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cutils/properties.h>
|
||||
|
||||
|
|
@ -36,11 +37,6 @@ struct memory_stat {
|
|||
int64_t process_start_time_ns;
|
||||
};
|
||||
|
||||
struct kernel_poll_info {
|
||||
int poll_fd;
|
||||
void (*handler)(int poll_fd);
|
||||
};
|
||||
|
||||
/*
|
||||
* These are defined in
|
||||
* 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,
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
|
@ -99,9 +103,7 @@ void stats_purge_tasknames();
|
|||
/**
|
||||
* Unregister a process taskname, e.g. after it has been killed.
|
||||
*/
|
||||
void stats_remove_taskname(int pid, int poll_fd);
|
||||
|
||||
bool init_poll_kernel(struct kernel_poll_info *poll_info);
|
||||
void stats_remove_taskname(int pid);
|
||||
|
||||
#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,
|
||||
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,
|
||||
int pid __unused, uid_t uid __unused) { return NULL; }
|
||||
|
||||
static inline void stats_store_taskname(int pid __unused, const char* taskname __unused,
|
||||
int poll_fd __unused) {}
|
||||
static inline void stats_store_taskname(int pid __unused, const char* taskname __unused) {}
|
||||
|
||||
static inline void stats_purge_tasknames() {}
|
||||
|
||||
static inline void stats_remove_taskname(int pid __unused, int poll_fd __unused) {}
|
||||
|
||||
static inline bool init_poll_kernel(struct kernel_poll_info *poll_info __unused) { return false; }
|
||||
static inline void stats_remove_taskname(int pid __unused) {}
|
||||
|
||||
#endif /* LMKD_LOG_STATS */
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue