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)248 static inline size_t lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet, pid_t pid, uid_t uid) {
249 packet[0] = htonl(LMK_PROCKILL);
250 packet[1] = htonl(pid);
251 packet[2] = htonl(uid);
252 return 3 * sizeof(int);
253 }
254
255 /*
256 * Prepare LMK_UPDATE_PROPS packet and return packet size in bytes.
257 * Warning: no checks performed, caller should ensure valid parameters.
258 */
lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet)259 static inline size_t lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet) {
260 packet[0] = htonl(LMK_UPDATE_PROPS);
261 return sizeof(int);
262 }
263
264 /*
265 * Prepare LMK_START_MONITORING packet and return packet size in bytes.
266 * Warning: no checks performed, caller should ensure valid parameters.
267 */
lmkd_pack_start_monitoring(LMKD_CTRL_PACKET packet)268 static inline size_t lmkd_pack_start_monitoring(LMKD_CTRL_PACKET packet) {
269 packet[0] = htonl(LMK_START_MONITORING);
270 return sizeof(int);
271 }
272
273 /*
274 * Prepare LMK_UPDATE_PROPS reply packet and return packet size in bytes.
275 * Warning: no checks performed, caller should ensure valid parameters.
276 */
lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet,int result)277 static inline size_t lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet, int result) {
278 packet[0] = htonl(LMK_UPDATE_PROPS);
279 packet[1] = htonl(result);
280 return 2 * sizeof(int);
281 }
282
283 /* LMK_UPDATE_PROPS reply payload */
284 struct lmk_update_props_reply {
285 int result;
286 };
287
288 /*
289 * For LMK_UPDATE_PROPS reply payload.
290 * Warning: no checks performed, caller should ensure valid parameters.
291 */
lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,struct lmk_update_props_reply * params)292 static inline void lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,
293 struct lmk_update_props_reply* params) {
294 params->result = ntohl(packet[1]);
295 }
296
297 /*
298 * Prepare LMK_BOOT_COMPLETED packet and return packet size in bytes.
299 * Warning: no checks performed, caller should ensure valid parameters.
300 */
lmkd_pack_set_boot_completed_notif(LMKD_CTRL_PACKET packet)301 static inline size_t lmkd_pack_set_boot_completed_notif(LMKD_CTRL_PACKET packet) {
302 packet[0] = htonl(LMK_BOOT_COMPLETED);
303 return sizeof(int);
304 }
305
306 /*
307 * Prepare LMK_BOOT_COMPLETED reply packet and return packet size in bytes.
308 * Warning: no checks performed, caller should ensure valid parameters.
309 */
lmkd_pack_set_boot_completed_notif_repl(LMKD_CTRL_PACKET packet,int result)310 static inline size_t lmkd_pack_set_boot_completed_notif_repl(LMKD_CTRL_PACKET packet, int result) {
311 packet[0] = htonl(LMK_BOOT_COMPLETED);
312 packet[1] = htonl(result);
313 return 2 * sizeof(int);
314 }
315
316 /* LMK_BOOT_COMPLETED reply payload */
317 struct lmk_boot_completed_notif_reply {
318 int result;
319 };
320
321 /*
322 * For LMK_BOOT_COMPLETED reply payload.
323 * Warning: no checks performed, caller should ensure valid parameters.
324 */
lmkd_pack_get_boot_completed_notif_repl(LMKD_CTRL_PACKET packet,struct lmk_boot_completed_notif_reply * params)325 static inline void lmkd_pack_get_boot_completed_notif_repl(
326 LMKD_CTRL_PACKET packet, struct lmk_boot_completed_notif_reply* params) {
327 params->result = ntohl(packet[1]);
328 }
329
330 #define PROCS_PRIO_MAX_RECORD_COUNT (CTRL_PACKET_MAX_SIZE / LMK_PROCPRIO_SIZE)
331
332 struct lmk_procs_prio {
333 struct lmk_procprio procs[PROCS_PRIO_MAX_RECORD_COUNT];
334 };
335
336 /*
337 * For LMK_PROCS_PRIO packet get its payload.
338 * Warning: no checks performed, caller should ensure valid parameters.
339 */
lmkd_pack_get_procs_prio(LMKD_CTRL_PACKET packet,struct lmk_procs_prio * params,const int field_count)340 static inline int lmkd_pack_get_procs_prio(LMKD_CTRL_PACKET packet, struct lmk_procs_prio* params,
341 const int field_count) {
342 if (field_count < LMK_PROCPRIO_FIELD_COUNT || (field_count % LMK_PROCPRIO_FIELD_COUNT) != 0)
343 return -1;
344 const int procs_count = (field_count / LMK_PROCPRIO_FIELD_COUNT);
345
346 /* Start packet at 1 since 0 is cmd type */
347 int packetIdx = 1;
348 for (int procs_idx = 0; procs_idx < procs_count; procs_idx++) {
349 params->procs[procs_idx].pid = (pid_t)ntohl(packet[packetIdx++]);
350 params->procs[procs_idx].uid = (uid_t)ntohl(packet[packetIdx++]);
351 params->procs[procs_idx].oomadj = ntohl(packet[packetIdx++]);
352 params->procs[procs_idx].ptype = (enum proc_type)ntohl(packet[packetIdx++]);
353 }
354
355 return procs_count;
356 }
357
358 /*
359 * Prepare LMK_PROCS_PRIO packet and return packet size in bytes.
360 * Warning: no checks performed, caller should ensure valid parameters.
361 */
lmkd_pack_set_procs_prio(LMKD_CTRL_PACKET packet,struct lmk_procs_prio * params,const int procs_count)362 static inline size_t lmkd_pack_set_procs_prio(LMKD_CTRL_PACKET packet,
363 struct lmk_procs_prio* params,
364 const int procs_count) {
365 packet[0] = htonl(LMK_PROCS_PRIO);
366 int packetIdx = 1;
367
368 for (int i = 0; i < procs_count; i++) {
369 packet[packetIdx++] = htonl(params->procs[i].pid);
370 packet[packetIdx++] = htonl(params->procs[i].uid);
371 packet[packetIdx++] = htonl(params->procs[i].oomadj);
372 packet[packetIdx++] = htonl((int)params->procs[i].ptype);
373 }
374
375 return packetIdx * sizeof(int);
376 }
377
378 __END_DECLS
379
380 #endif /* _LMKD_H_ */
381