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