1 /*
2  *  Copyright 2018 Google, Inc
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  */
16 
17 #ifndef _LMKD_H_
18 #define _LMKD_H_
19 
20 #include <arpa/inet.h>
21 #include <sys/cdefs.h>
22 #include <sys/types.h>
23 
24 __BEGIN_DECLS
25 
26 /*
27  * Supported LMKD commands
28  */
29 enum lmk_cmd {
30     LMK_TARGET = 0,         /* Associate minfree with oom_adj_score */
31     LMK_PROCPRIO,           /* Register a process and set its oom_adj_score */
32     LMK_PROCREMOVE,         /* Unregister a process */
33     LMK_PROCPURGE,          /* Purge all registered processes */
34     LMK_GETKILLCNT,         /* Get number of kills */
35     LMK_SUBSCRIBE,          /* Subscribe for asynchronous events */
36     LMK_PROCKILL,           /* Unsolicited msg to subscribed clients on proc kills */
37     LMK_UPDATE_PROPS,       /* Reinit properties */
38     LMK_STAT_KILL_OCCURRED, /* Unsolicited msg to subscribed clients on proc kills for statsd log */
39     LMK_START_MONITORING,   /* Start psi monitoring if it was skipped earlier */
40     LMK_BOOT_COMPLETED,     /* Notify LMKD boot is completed */
41     LMK_PROCS_PRIO,         /* Register processes and set the same oom_adj_score */
42 };
43 
44 /*
45  * Max number of targets in LMK_TARGET command.
46  */
47 #define MAX_TARGETS 6
48 
49 /*
50  * Max packet length in bytes.
51  * Longest packet is LMK_TARGET followed by MAX_TARGETS
52  * of minfree and oom_adj_score values
53  */
54 #define CTRL_PACKET_MAX_SIZE (sizeof(int) * (MAX_TARGETS * 2 + 1))
55 
56 /* LMKD packet - first int is lmk_cmd followed by payload */
57 typedef int LMKD_CTRL_PACKET[CTRL_PACKET_MAX_SIZE / sizeof(int)];
58 
59 /* Get LMKD packet command */
lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack)60 static inline enum lmk_cmd lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack) {
61     return (enum lmk_cmd)ntohl(pack[0]);
62 }
63 
64 /* LMK_TARGET packet payload */
65 struct lmk_target {
66     int minfree;
67     int oom_adj_score;
68 };
69 
70 /*
71  * For LMK_TARGET packet get target_idx-th payload.
72  * Warning: no checks performed, caller should ensure valid parameters.
73  */
lmkd_pack_get_target(LMKD_CTRL_PACKET packet,int target_idx,struct lmk_target * target)74 static inline void lmkd_pack_get_target(LMKD_CTRL_PACKET packet, int target_idx,
75                                         struct lmk_target* target) {
76     target->minfree = ntohl(packet[target_idx * 2 + 1]);
77     target->oom_adj_score = ntohl(packet[target_idx * 2 + 2]);
78 }
79 
80 /*
81  * Prepare LMK_TARGET packet and return packet size in bytes.
82  * Warning: no checks performed, caller should ensure valid parameters.
83  */
lmkd_pack_set_target(LMKD_CTRL_PACKET packet,struct lmk_target * targets,size_t target_cnt)84 static inline size_t lmkd_pack_set_target(LMKD_CTRL_PACKET packet, struct lmk_target* targets,
85                                           size_t target_cnt) {
86     int idx = 0;
87     packet[idx++] = htonl(LMK_TARGET);
88     while (target_cnt) {
89         packet[idx++] = htonl(targets->minfree);
90         packet[idx++] = htonl(targets->oom_adj_score);
91         targets++;
92         target_cnt--;
93     }
94     return idx * sizeof(int);
95 }
96 
97 /* Process types for lmk_procprio.ptype */
98 enum proc_type {
99     PROC_TYPE_FIRST,
100     PROC_TYPE_APP = PROC_TYPE_FIRST,
101     PROC_TYPE_SERVICE,
102     PROC_TYPE_COUNT,
103 };
104 
105 /* LMK_PROCPRIO packet payload */
106 struct lmk_procprio {
107     pid_t pid;
108     uid_t uid;
109     int oomadj;
110     enum proc_type ptype;
111 };
112 #define LMK_PROCPRIO_FIELD_COUNT 4
113 #define LMK_PROCPRIO_SIZE (LMK_PROCPRIO_FIELD_COUNT * sizeof(int))
114 
115 /*
116  * For LMK_PROCPRIO packet get its payload.
117  * Warning: no checks performed, caller should ensure valid parameters.
118  */
lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet,int field_count,struct lmk_procprio * params)119 static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet, int field_count,
120                                           struct lmk_procprio* params) {
121     params->pid = (pid_t)ntohl(packet[1]);
122     params->uid = (uid_t)ntohl(packet[2]);
123     params->oomadj = ntohl(packet[3]);
124     /* if field is missing assume PROC_TYPE_APP for backward compatibility */
125     params->ptype = field_count > 3 ? (enum proc_type)ntohl(packet[4]) : PROC_TYPE_APP;
126 }
127 
128 /*
129  * Prepare LMK_PROCPRIO packet and return packet size in bytes.
130  * Warning: no checks performed, caller should ensure valid parameters.
131  */
lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet,struct lmk_procprio * params)132 static inline size_t lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet, struct lmk_procprio* params) {
133     packet[0] = htonl(LMK_PROCPRIO);
134     packet[1] = htonl(params->pid);
135     packet[2] = htonl(params->uid);
136     packet[3] = htonl(params->oomadj);
137     packet[4] = htonl((int)params->ptype);
138     return 5 * sizeof(int);
139 }
140 
141 /* LMK_PROCREMOVE packet payload */
142 struct lmk_procremove {
143     pid_t pid;
144 };
145 
146 /*
147  * For LMK_PROCREMOVE packet get its payload.
148  * Warning: no checks performed, caller should ensure valid parameters.
149  */
lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,struct lmk_procremove * params)150 static inline void lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,
151                                             struct lmk_procremove* params) {
152     params->pid = (pid_t)ntohl(packet[1]);
153 }
154 
155 /*
156  * Prepare LMK_PROCREMOVE packet and return packet size in bytes.
157  * Warning: no checks performed, caller should ensure valid parameters.
158  */
lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,struct lmk_procremove * params)159 static inline size_t lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,
160                                               struct lmk_procremove* params) {
161     packet[0] = htonl(LMK_PROCREMOVE);
162     packet[1] = htonl(params->pid);
163     return 2 * sizeof(int);
164 }
165 
166 /*
167  * Prepare LMK_PROCPURGE packet and return packet size in bytes.
168  * Warning: no checks performed, caller should ensure valid parameters.
169  */
lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet)170 static inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
171     packet[0] = htonl(LMK_PROCPURGE);
172     return sizeof(int);
173 }
174 
175 /* LMK_GETKILLCNT packet payload */
176 struct lmk_getkillcnt {
177     int min_oomadj;
178     int max_oomadj;
179 };
180 
181 /*
182  * For LMK_GETKILLCNT packet get its payload.
183  * Warning: no checks performed, caller should ensure valid parameters.
184  */
lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,struct lmk_getkillcnt * params)185 static inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
186                                             struct lmk_getkillcnt* params) {
187     params->min_oomadj = ntohl(packet[1]);
188     params->max_oomadj = ntohl(packet[2]);
189 }
190 
191 /*
192  * Prepare LMK_GETKILLCNT packet and return packet size in bytes.
193  * Warning: no checks performed, caller should ensure valid parameters.
194  */
lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,struct lmk_getkillcnt * params)195 static inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
196                                               struct lmk_getkillcnt* params) {
197     packet[0] = htonl(LMK_GETKILLCNT);
198     packet[1] = htonl(params->min_oomadj);
199     packet[2] = htonl(params->max_oomadj);
200     return 3 * sizeof(int);
201 }
202 
203 /*
204  * Prepare LMK_GETKILLCNT reply packet and return packet size in bytes.
205  * Warning: no checks performed, caller should ensure valid parameters.
206  */
lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet,int kill_cnt)207 static inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
208     packet[0] = htonl(LMK_GETKILLCNT);
209     packet[1] = htonl(kill_cnt);
210     return 2 * sizeof(int);
211 }
212 
213 /* Types of asynchronous events sent from lmkd to its clients */
214 enum async_event_type {
215     LMK_ASYNC_EVENT_FIRST,
216     LMK_ASYNC_EVENT_KILL = LMK_ASYNC_EVENT_FIRST,
217     LMK_ASYNC_EVENT_STAT,
218     LMK_ASYNC_EVENT_COUNT,
219 };
220 
221 /* LMK_SUBSCRIBE packet payload */
222 struct lmk_subscribe {
223     enum async_event_type evt_type;
224 };
225 
226 /*
227  * For LMK_SUBSCRIBE packet get its payload.
228  * Warning: no checks performed, caller should ensure valid parameters.
229  */
lmkd_pack_get_subscribe(LMKD_CTRL_PACKET packet,struct lmk_subscribe * params)230 static inline void lmkd_pack_get_subscribe(LMKD_CTRL_PACKET packet, struct lmk_subscribe* params) {
231     params->evt_type = (enum async_event_type)ntohl(packet[1]);
232 }
233 
234 /**
235  * Prepare LMK_SUBSCRIBE packet and return packet size in bytes.
236  * Warning: no checks performed, caller should ensure valid parameters.
237  */
lmkd_pack_set_subscribe(LMKD_CTRL_PACKET packet,enum async_event_type evt_type)238 static inline size_t lmkd_pack_set_subscribe(LMKD_CTRL_PACKET packet, enum async_event_type evt_type) {
239     packet[0] = htonl(LMK_SUBSCRIBE);
240     packet[1] = htonl((int)evt_type);
241     return 2 * sizeof(int);
242 }
243 
244 /**
245  * Prepare LMK_PROCKILL unsolicited packet and return packet size in bytes.
246  * Warning: no checks performed, caller should ensure valid parameters.
247  */
lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet,pid_t pid,uid_t uid,int rss_kb)248 static inline size_t lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet, pid_t pid, uid_t uid,
249                                              int rss_kb) {
250     packet[0] = htonl(LMK_PROCKILL);
251     packet[1] = htonl(pid);
252     packet[2] = htonl(uid);
253     packet[3] = htonl(rss_kb);
254 
255     return 4 * sizeof(int);
256 }
257 
258 /*
259  * Prepare LMK_UPDATE_PROPS packet and return packet size in bytes.
260  * Warning: no checks performed, caller should ensure valid parameters.
261  */
lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet)262 static inline size_t lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet) {
263     packet[0] = htonl(LMK_UPDATE_PROPS);
264     return sizeof(int);
265 }
266 
267 /*
268  * Prepare LMK_START_MONITORING packet and return packet size in bytes.
269  * Warning: no checks performed, caller should ensure valid parameters.
270  */
lmkd_pack_start_monitoring(LMKD_CTRL_PACKET packet)271 static inline size_t lmkd_pack_start_monitoring(LMKD_CTRL_PACKET packet) {
272     packet[0] = htonl(LMK_START_MONITORING);
273     return sizeof(int);
274 }
275 
276 /*
277  * Prepare LMK_UPDATE_PROPS reply packet and return packet size in bytes.
278  * Warning: no checks performed, caller should ensure valid parameters.
279  */
lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet,int result)280 static inline size_t lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet, int result) {
281     packet[0] = htonl(LMK_UPDATE_PROPS);
282     packet[1] = htonl(result);
283     return 2 * sizeof(int);
284 }
285 
286 /* LMK_UPDATE_PROPS reply payload */
287 struct lmk_update_props_reply {
288     int result;
289 };
290 
291 /*
292  * For LMK_UPDATE_PROPS reply payload.
293  * Warning: no checks performed, caller should ensure valid parameters.
294  */
lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,struct lmk_update_props_reply * params)295 static inline void lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,
296                                           struct lmk_update_props_reply* params) {
297     params->result = ntohl(packet[1]);
298 }
299 
300 /*
301  * Prepare LMK_BOOT_COMPLETED packet and return packet size in bytes.
302  * Warning: no checks performed, caller should ensure valid parameters.
303  */
lmkd_pack_set_boot_completed_notif(LMKD_CTRL_PACKET packet)304 static inline size_t lmkd_pack_set_boot_completed_notif(LMKD_CTRL_PACKET packet) {
305     packet[0] = htonl(LMK_BOOT_COMPLETED);
306     return sizeof(int);
307 }
308 
309 /*
310  * Prepare LMK_BOOT_COMPLETED reply packet and return packet size in bytes.
311  * Warning: no checks performed, caller should ensure valid parameters.
312  */
lmkd_pack_set_boot_completed_notif_repl(LMKD_CTRL_PACKET packet,int result)313 static inline size_t lmkd_pack_set_boot_completed_notif_repl(LMKD_CTRL_PACKET packet, int result) {
314     packet[0] = htonl(LMK_BOOT_COMPLETED);
315     packet[1] = htonl(result);
316     return 2 * sizeof(int);
317 }
318 
319 /* LMK_BOOT_COMPLETED reply payload */
320 struct lmk_boot_completed_notif_reply {
321     int result;
322 };
323 
324 /*
325  * For LMK_BOOT_COMPLETED reply payload.
326  * Warning: no checks performed, caller should ensure valid parameters.
327  */
lmkd_pack_get_boot_completed_notif_repl(LMKD_CTRL_PACKET packet,struct lmk_boot_completed_notif_reply * params)328 static inline void lmkd_pack_get_boot_completed_notif_repl(
329         LMKD_CTRL_PACKET packet, struct lmk_boot_completed_notif_reply* params) {
330     params->result = ntohl(packet[1]);
331 }
332 
333 #define PROCS_PRIO_MAX_RECORD_COUNT (CTRL_PACKET_MAX_SIZE / LMK_PROCPRIO_SIZE)
334 
335 struct lmk_procs_prio {
336     struct lmk_procprio procs[PROCS_PRIO_MAX_RECORD_COUNT];
337 };
338 
339 /*
340  * For LMK_PROCS_PRIO packet get its payload.
341  * Warning: no checks performed, caller should ensure valid parameters.
342  */
lmkd_pack_get_procs_prio(LMKD_CTRL_PACKET packet,struct lmk_procs_prio * params,const int field_count)343 static inline int lmkd_pack_get_procs_prio(LMKD_CTRL_PACKET packet, struct lmk_procs_prio* params,
344                                            const int field_count) {
345     if (field_count < LMK_PROCPRIO_FIELD_COUNT || (field_count % LMK_PROCPRIO_FIELD_COUNT) != 0)
346         return -1;
347     const int procs_count = (field_count / LMK_PROCPRIO_FIELD_COUNT);
348 
349     /* Start packet at 1 since 0 is cmd type */
350     int packetIdx = 1;
351     for (int procs_idx = 0; procs_idx < procs_count; procs_idx++) {
352         params->procs[procs_idx].pid = (pid_t)ntohl(packet[packetIdx++]);
353         params->procs[procs_idx].uid = (uid_t)ntohl(packet[packetIdx++]);
354         params->procs[procs_idx].oomadj = ntohl(packet[packetIdx++]);
355         params->procs[procs_idx].ptype = (enum proc_type)ntohl(packet[packetIdx++]);
356     }
357 
358     return procs_count;
359 }
360 
361 /*
362  * Prepare LMK_PROCS_PRIO packet and return packet size in bytes.
363  * Warning: no checks performed, caller should ensure valid parameters.
364  */
lmkd_pack_set_procs_prio(LMKD_CTRL_PACKET packet,struct lmk_procs_prio * params,const int procs_count)365 static inline size_t lmkd_pack_set_procs_prio(LMKD_CTRL_PACKET packet,
366                                               struct lmk_procs_prio* params,
367                                               const int procs_count) {
368     packet[0] = htonl(LMK_PROCS_PRIO);
369     int packetIdx = 1;
370 
371     for (int i = 0; i < procs_count; i++) {
372         packet[packetIdx++] = htonl(params->procs[i].pid);
373         packet[packetIdx++] = htonl(params->procs[i].uid);
374         packet[packetIdx++] = htonl(params->procs[i].oomadj);
375         packet[packetIdx++] = htonl((int)params->procs[i].ptype);
376     }
377 
378     return packetIdx * sizeof(int);
379 }
380 
381 __END_DECLS
382 
383 #endif /* _LMKD_H_ */
384