lmkd: Add command to get number of kills
Intrduce LMK_GETKILLCNT command for ActivityManager to get the number of kills from lmkd. Bug: 117126077 Test: used lmkd_unit_test to verify correct reporting Change-Id: I09c720a7176b4df95efc544177cd2694f8d791be Signed-off-by: Suren Baghdasaryan <surenb@google.com>
This commit is contained in:
parent
ac305c82d6
commit
d4a29903c0
2 changed files with 141 additions and 1 deletions
|
@ -31,6 +31,7 @@ enum lmk_cmd {
|
|||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -152,6 +153,44 @@ inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
|
|||
return sizeof(int);
|
||||
}
|
||||
|
||||
/* LMK_GETKILLCNT packet payload */
|
||||
struct lmk_getkillcnt {
|
||||
int min_oomadj;
|
||||
int max_oomadj;
|
||||
};
|
||||
|
||||
/*
|
||||
* For LMK_GETKILLCNT packet get its payload.
|
||||
* Warning: no checks performed, caller should ensure valid parameters.
|
||||
*/
|
||||
inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
|
||||
struct lmk_getkillcnt *params) {
|
||||
params->min_oomadj = ntohl(packet[1]);
|
||||
params->max_oomadj = ntohl(packet[2]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare LMK_GETKILLCNT packet and return packet size in bytes.
|
||||
* Warning: no checks performed, caller should ensure valid parameters.
|
||||
*/
|
||||
inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
|
||||
struct lmk_getkillcnt *params) {
|
||||
packet[0] = htonl(LMK_GETKILLCNT);
|
||||
packet[1] = htonl(params->min_oomadj);
|
||||
packet[2] = htonl(params->max_oomadj);
|
||||
return 3 * sizeof(int);
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare LMK_GETKILLCNT reply packet and return packet size in bytes.
|
||||
* Warning: no checks performed, caller should ensure valid parameters.
|
||||
*/
|
||||
inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
|
||||
packet[0] = htonl(LMK_GETKILLCNT);
|
||||
packet[1] = htonl(kill_cnt);
|
||||
return 2 * sizeof(int);
|
||||
}
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _LMKD_H_ */
|
||||
|
|
103
lmkd/lmkd.c
103
lmkd/lmkd.c
|
@ -313,7 +313,20 @@ static struct proc *pidhash[PIDHASH_SZ];
|
|||
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
|
||||
|
||||
#define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
|
||||
static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
|
||||
#define ADJTOSLOT_COUNT (ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1)
|
||||
static struct adjslot_list procadjslot_list[ADJTOSLOT_COUNT];
|
||||
|
||||
#define MAX_DISTINCT_OOM_ADJ 32
|
||||
#define KILLCNT_INVALID_IDX 0xFF
|
||||
/*
|
||||
* Because killcnt array is sparse a two-level indirection is used
|
||||
* to keep the size small. killcnt_idx stores index of the element in
|
||||
* killcnt array. Index KILLCNT_INVALID_IDX indicates an unused slot.
|
||||
*/
|
||||
static uint8_t killcnt_idx[ADJTOSLOT_COUNT];
|
||||
static uint16_t killcnt[MAX_DISTINCT_OOM_ADJ];
|
||||
static int killcnt_free_idx = 0;
|
||||
static uint32_t killcnt_total = 0;
|
||||
|
||||
/* PAGE_SIZE / 1024 */
|
||||
static long page_k;
|
||||
|
@ -644,6 +657,67 @@ static void cmd_procpurge() {
|
|||
memset(&pidhash[0], 0, sizeof(pidhash));
|
||||
}
|
||||
|
||||
static void inc_killcnt(int oomadj) {
|
||||
int slot = ADJTOSLOT(oomadj);
|
||||
uint8_t idx = killcnt_idx[slot];
|
||||
|
||||
if (idx == KILLCNT_INVALID_IDX) {
|
||||
/* index is not assigned for this oomadj */
|
||||
if (killcnt_free_idx < MAX_DISTINCT_OOM_ADJ) {
|
||||
killcnt_idx[slot] = killcnt_free_idx;
|
||||
killcnt[killcnt_free_idx] = 1;
|
||||
killcnt_free_idx++;
|
||||
} else {
|
||||
ALOGW("Number of distinct oomadj levels exceeds %d",
|
||||
MAX_DISTINCT_OOM_ADJ);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* wraparound is highly unlikely and is detectable using total
|
||||
* counter because it has to be equal to the sum of all counters
|
||||
*/
|
||||
killcnt[idx]++;
|
||||
}
|
||||
/* increment total kill counter */
|
||||
killcnt_total++;
|
||||
}
|
||||
|
||||
static int get_killcnt(int min_oomadj, int max_oomadj) {
|
||||
int slot;
|
||||
int count = 0;
|
||||
|
||||
if (min_oomadj > max_oomadj)
|
||||
return 0;
|
||||
|
||||
/* special case to get total kill count */
|
||||
if (min_oomadj > OOM_SCORE_ADJ_MAX)
|
||||
return killcnt_total;
|
||||
|
||||
while (min_oomadj <= max_oomadj &&
|
||||
(slot = ADJTOSLOT(min_oomadj)) < ADJTOSLOT_COUNT) {
|
||||
uint8_t idx = killcnt_idx[slot];
|
||||
if (idx != KILLCNT_INVALID_IDX) {
|
||||
count += killcnt[idx];
|
||||
}
|
||||
min_oomadj++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int cmd_getkillcnt(LMKD_CTRL_PACKET packet) {
|
||||
struct lmk_getkillcnt params;
|
||||
|
||||
if (use_inkernel_interface) {
|
||||
/* kernel driver does not expose this information */
|
||||
return 0;
|
||||
}
|
||||
|
||||
lmkd_pack_get_getkillcnt(packet, ¶ms);
|
||||
|
||||
return get_killcnt(params.min_oomadj, params.max_oomadj);
|
||||
}
|
||||
|
||||
static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
|
||||
int i;
|
||||
struct lmk_target target;
|
||||
|
@ -748,12 +822,28 @@ static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) {
|
|||
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;
|
||||
int len;
|
||||
enum lmk_cmd cmd;
|
||||
int nargs;
|
||||
int targets;
|
||||
int kill_cnt;
|
||||
|
||||
len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE);
|
||||
if (len <= 0)
|
||||
|
@ -791,6 +881,14 @@ static void ctrl_command_handler(int dsock_idx) {
|
|||
goto wronglen;
|
||||
cmd_procpurge();
|
||||
break;
|
||||
case LMK_GETKILLCNT:
|
||||
if (nargs != 2)
|
||||
goto wronglen;
|
||||
kill_cnt = cmd_getkillcnt(packet);
|
||||
len = lmkd_pack_set_getkillcnt_repl(packet, kill_cnt);
|
||||
if (ctrl_data_write(dsock_idx, (char *)packet, len) != len)
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
ALOGE("Received unknown command code %d", cmd);
|
||||
return;
|
||||
|
@ -1200,6 +1298,7 @@ static int kill_one_process(struct proc* procp) {
|
|||
|
||||
/* CAP_KILL required */
|
||||
r = kill(pid, SIGKILL);
|
||||
inc_killcnt(procp->oomadj);
|
||||
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
|
||||
taskname, pid, uid, procp->oomadj, tasksize * page_k);
|
||||
|
||||
|
@ -1700,6 +1799,8 @@ static int init(void) {
|
|||
procadjslot_list[i].prev = &procadjslot_list[i];
|
||||
}
|
||||
|
||||
memset(killcnt_idx, KILLCNT_INVALID_IDX, sizeof(killcnt_idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue