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_STAT_STATE_CHANGED, /* Unsolicited msg to subscribed clients on state changed */
40 };
41 
42 /*
43  * Max number of targets in LMK_TARGET command.
44  */
45 #define MAX_TARGETS 6
46 
47 /*
48  * Max packet length in bytes.
49  * Longest packet is LMK_TARGET followed by MAX_TARGETS
50  * of minfree and oom_adj_score values
51  */
52 #define CTRL_PACKET_MAX_SIZE (sizeof(int) * (MAX_TARGETS * 2 + 1))
53 
54 /* LMKD packet - first int is lmk_cmd followed by payload */
55 typedef int LMKD_CTRL_PACKET[CTRL_PACKET_MAX_SIZE / sizeof(int)];
56 
57 /* Get LMKD packet command */
lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack)58 static inline enum lmk_cmd lmkd_pack_get_cmd(LMKD_CTRL_PACKET pack) {
59     return (enum lmk_cmd)ntohl(pack[0]);
60 }
61 
62 /* LMK_TARGET packet payload */
63 struct lmk_target {
64     int minfree;
65     int oom_adj_score;
66 };
67 
68 /*
69  * For LMK_TARGET packet get target_idx-th payload.
70  * Warning: no checks performed, caller should ensure valid parameters.
71  */
lmkd_pack_get_target(LMKD_CTRL_PACKET packet,int target_idx,struct lmk_target * target)72 static inline void lmkd_pack_get_target(LMKD_CTRL_PACKET packet, int target_idx,
73                                         struct lmk_target* target) {
74     target->minfree = ntohl(packet[target_idx * 2 + 1]);
75     target->oom_adj_score = ntohl(packet[target_idx * 2 + 2]);
76 }
77 
78 /*
79  * Prepare LMK_TARGET packet and return packet size in bytes.
80  * Warning: no checks performed, caller should ensure valid parameters.
81  */
lmkd_pack_set_target(LMKD_CTRL_PACKET packet,struct lmk_target * targets,size_t target_cnt)82 static inline size_t lmkd_pack_set_target(LMKD_CTRL_PACKET packet, struct lmk_target* targets,
83                                           size_t target_cnt) {
84     int idx = 0;
85     packet[idx++] = htonl(LMK_TARGET);
86     while (target_cnt) {
87         packet[idx++] = htonl(targets->minfree);
88         packet[idx++] = htonl(targets->oom_adj_score);
89         targets++;
90         target_cnt--;
91     }
92     return idx * sizeof(int);
93 }
94 
95 /* Process types for lmk_procprio.ptype */
96 enum proc_type {
97     PROC_TYPE_FIRST,
98     PROC_TYPE_APP = PROC_TYPE_FIRST,
99     PROC_TYPE_SERVICE,
100     PROC_TYPE_COUNT,
101 };
102 
103 /* LMK_PROCPRIO packet payload */
104 struct lmk_procprio {
105     pid_t pid;
106     uid_t uid;
107     int oomadj;
108     enum proc_type ptype;
109 };
110 
111 /*
112  * For LMK_PROCPRIO packet get its payload.
113  * Warning: no checks performed, caller should ensure valid parameters.
114  */
lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet,int field_count,struct lmk_procprio * params)115 static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet, int field_count,
116                                           struct lmk_procprio* params) {
117     params->pid = (pid_t)ntohl(packet[1]);
118     params->uid = (uid_t)ntohl(packet[2]);
119     params->oomadj = ntohl(packet[3]);
120     /* if field is missing assume PROC_TYPE_APP for backward compatibility */
121     params->ptype = field_count > 3 ? (enum proc_type)ntohl(packet[4]) : PROC_TYPE_APP;
122 }
123 
124 /*
125  * Prepare LMK_PROCPRIO packet and return packet size in bytes.
126  * Warning: no checks performed, caller should ensure valid parameters.
127  */
lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet,struct lmk_procprio * params)128 static inline size_t lmkd_pack_set_procprio(LMKD_CTRL_PACKET packet, struct lmk_procprio* params) {
129     packet[0] = htonl(LMK_PROCPRIO);
130     packet[1] = htonl(params->pid);
131     packet[2] = htonl(params->uid);
132     packet[3] = htonl(params->oomadj);
133     packet[4] = htonl((int)params->ptype);
134     return 5 * sizeof(int);
135 }
136 
137 /* LMK_PROCREMOVE packet payload */
138 struct lmk_procremove {
139     pid_t pid;
140 };
141 
142 /*
143  * For LMK_PROCREMOVE packet get its payload.
144  * Warning: no checks performed, caller should ensure valid parameters.
145  */
lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,struct lmk_procremove * params)146 static inline void lmkd_pack_get_procremove(LMKD_CTRL_PACKET packet,
147                                             struct lmk_procremove* params) {
148     params->pid = (pid_t)ntohl(packet[1]);
149 }
150 
151 /*
152  * Prepare LMK_PROCREMOVE packet and return packet size in bytes.
153  * Warning: no checks performed, caller should ensure valid parameters.
154  */
lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,struct lmk_procremove * params)155 static inline size_t lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,
156                                               struct lmk_procremove* params) {
157     packet[0] = htonl(LMK_PROCREMOVE);
158     packet[1] = htonl(params->pid);
159     return 2 * sizeof(int);
160 }
161 
162 /*
163  * Prepare LMK_PROCPURGE packet and return packet size in bytes.
164  * Warning: no checks performed, caller should ensure valid parameters.
165  */
lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet)166 static inline size_t lmkd_pack_set_procpurge(LMKD_CTRL_PACKET packet) {
167     packet[0] = htonl(LMK_PROCPURGE);
168     return sizeof(int);
169 }
170 
171 /* LMK_GETKILLCNT packet payload */
172 struct lmk_getkillcnt {
173     int min_oomadj;
174     int max_oomadj;
175 };
176 
177 /*
178  * For LMK_GETKILLCNT packet get its payload.
179  * Warning: no checks performed, caller should ensure valid parameters.
180  */
lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,struct lmk_getkillcnt * params)181 static inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
182                                             struct lmk_getkillcnt* params) {
183     params->min_oomadj = ntohl(packet[1]);
184     params->max_oomadj = ntohl(packet[2]);
185 }
186 
187 /*
188  * Prepare LMK_GETKILLCNT packet and return packet size in bytes.
189  * Warning: no checks performed, caller should ensure valid parameters.
190  */
lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,struct lmk_getkillcnt * params)191 static inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
192                                               struct lmk_getkillcnt* params) {
193     packet[0] = htonl(LMK_GETKILLCNT);
194     packet[1] = htonl(params->min_oomadj);
195     packet[2] = htonl(params->max_oomadj);
196     return 3 * sizeof(int);
197 }
198 
199 /*
200  * Prepare LMK_GETKILLCNT reply packet and return packet size in bytes.
201  * Warning: no checks performed, caller should ensure valid parameters.
202  */
lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet,int kill_cnt)203 static inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
204     packet[0] = htonl(LMK_GETKILLCNT);
205     packet[1] = htonl(kill_cnt);
206     return 2 * sizeof(int);
207 }
208 
209 /* Types of asynchronous events sent from lmkd to its clients */
210 enum async_event_type {
211     LMK_ASYNC_EVENT_FIRST,
212     LMK_ASYNC_EVENT_KILL = LMK_ASYNC_EVENT_FIRST,
213     LMK_ASYNC_EVENT_STAT,
214     LMK_ASYNC_EVENT_COUNT,
215 };
216 
217 /* LMK_SUBSCRIBE packet payload */
218 struct lmk_subscribe {
219     enum async_event_type evt_type;
220 };
221 
222 /*
223  * For LMK_SUBSCRIBE packet get its payload.
224  * Warning: no checks performed, caller should ensure valid parameters.
225  */
lmkd_pack_get_subscribe(LMKD_CTRL_PACKET packet,struct lmk_subscribe * params)226 static inline void lmkd_pack_get_subscribe(LMKD_CTRL_PACKET packet, struct lmk_subscribe* params) {
227     params->evt_type = (enum async_event_type)ntohl(packet[1]);
228 }
229 
230 /**
231  * Prepare LMK_SUBSCRIBE packet and return packet size in bytes.
232  * Warning: no checks performed, caller should ensure valid parameters.
233  */
lmkd_pack_set_subscribe(LMKD_CTRL_PACKET packet,enum async_event_type evt_type)234 static inline size_t lmkd_pack_set_subscribe(LMKD_CTRL_PACKET packet, enum async_event_type evt_type) {
235     packet[0] = htonl(LMK_SUBSCRIBE);
236     packet[1] = htonl((int)evt_type);
237     return 2 * sizeof(int);
238 }
239 
240 /**
241  * Prepare LMK_PROCKILL unsolicited packet and return packet size in bytes.
242  * Warning: no checks performed, caller should ensure valid parameters.
243  */
lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet,pid_t pid,uid_t uid)244 static inline size_t lmkd_pack_set_prockills(LMKD_CTRL_PACKET packet, pid_t pid, uid_t uid) {
245     packet[0] = htonl(LMK_PROCKILL);
246     packet[1] = htonl(pid);
247     packet[2] = htonl(uid);
248     return 3 * sizeof(int);
249 }
250 
251 /*
252  * Prepare LMK_UPDATE_PROPS packet and return packet size in bytes.
253  * Warning: no checks performed, caller should ensure valid parameters.
254  */
lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet)255 static inline size_t lmkd_pack_set_update_props(LMKD_CTRL_PACKET packet) {
256     packet[0] = htonl(LMK_UPDATE_PROPS);
257     return sizeof(int);
258 }
259 
260 /*
261  * Prepare LMK_UPDATE_PROPS reply packet and return packet size in bytes.
262  * Warning: no checks performed, caller should ensure valid parameters.
263  */
lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet,int result)264 static inline size_t lmkd_pack_set_update_props_repl(LMKD_CTRL_PACKET packet, int result) {
265     packet[0] = htonl(LMK_UPDATE_PROPS);
266     packet[1] = htonl(result);
267     return 2 * sizeof(int);
268 }
269 
270 /* LMK_PROCPRIO reply payload */
271 struct lmk_update_props_reply {
272     int result;
273 };
274 
275 /*
276  * For LMK_UPDATE_PROPS reply payload.
277  * Warning: no checks performed, caller should ensure valid parameters.
278  */
lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,struct lmk_update_props_reply * params)279 static inline void lmkd_pack_get_update_props_repl(LMKD_CTRL_PACKET packet,
280                                           struct lmk_update_props_reply* params) {
281     params->result = ntohl(packet[1]);
282 }
283 
284 __END_DECLS
285 
286 #endif /* _LMKD_H_ */
287