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 #include <assert.h>
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <log/log.h>
21 #include <log/log_id.h>
22 #include <statslog.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/endian.h>
28 #include <sys/param.h>
29 #include <sys/uio.h>
30 #include <time.h>
31 #include <unistd.h>
32
33 #include <string>
34
35 #include <processgroup/processgroup.h>
36
37 #ifdef LMKD_LOG_STATS
38
39 #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
40 #define STRINGIFY_INTERNAL(x) #x
41
42 /**
43 * Used to make sure that the payload is always smaller than LMKD_REPLY_MAX_SIZE
44 */
45 #define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
46
47 static bool enable_stats_log = property_get_bool("ro.lmk.log_stats", true);
48
49 struct proc {
50 int pid;
51 char taskname[MAX_TASKNAME_LEN];
52 struct proc* pidhash_next;
53 };
54
55 #define PIDHASH_SZ 1024
56 static struct proc** pidhash = NULL;
57 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
58
pid_lookup(int pid)59 static struct proc* pid_lookup(int pid) {
60 struct proc* procp;
61
62 if (!pidhash) return NULL;
63
64 for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid; procp = procp->pidhash_next)
65 ;
66
67 return procp;
68 }
69
memory_stat_parse_line(char * line,struct memory_stat * mem_st)70 static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) {
71 char key[MAX_TASKNAME_LEN + 1];
72 int64_t value;
73
74 sscanf(line, "%" STRINGIFY(MAX_TASKNAME_LEN) "s %" SCNd64 "", key, &value);
75
76 if (strcmp(key, "total_") < 0) {
77 return;
78 }
79
80 if (!strcmp(key, "total_pgfault"))
81 mem_st->pgfault = value;
82 else if (!strcmp(key, "total_pgmajfault"))
83 mem_st->pgmajfault = value;
84 else if (!strcmp(key, "total_rss"))
85 mem_st->rss_in_bytes = value;
86 else if (!strcmp(key, "total_cache"))
87 mem_st->cache_in_bytes = value;
88 else if (!strcmp(key, "total_swap"))
89 mem_st->swap_in_bytes = value;
90 }
91
memory_stat_from_cgroup(struct memory_stat * mem_st,int pid,uid_t uid __unused)92 static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid __unused) {
93 std::string path;
94 if (!CgroupGetAttributePathForTask("MemStats", pid, &path)) {
95 ALOGE("Querying MemStats path failed");
96 return -1;
97 }
98
99 FILE* fp = fopen(path.c_str(), "r");
100
101 if (fp == NULL) {
102 return -1;
103 }
104
105 char buf[PAGE_SIZE];
106 while (fgets(buf, PAGE_SIZE, fp) != NULL) {
107 memory_stat_parse_line(buf, mem_st);
108 }
109 fclose(fp);
110
111 return 0;
112 }
113
memory_stat_from_procfs(struct memory_stat * mem_st,int pid)114 static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
115 char path[PATH_MAX];
116 char buffer[PROC_STAT_BUFFER_SIZE];
117 int fd, ret;
118
119 snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
120 if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
121 return -1;
122 }
123
124 ret = read(fd, buffer, sizeof(buffer));
125 if (ret < 0) {
126 close(fd);
127 return -1;
128 }
129 close(fd);
130
131 // field 10 is pgfault
132 // field 12 is pgmajfault
133 // field 22 is starttime
134 int64_t pgfault = 0, pgmajfault = 0, starttime = 0;
135 if (sscanf(buffer,
136 "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
137 "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
138 "%" SCNd64 "",
139 &pgfault, &pgmajfault, &starttime) != 3) {
140 return -1;
141 }
142 mem_st->pgfault = pgfault;
143 mem_st->pgmajfault = pgmajfault;
144 mem_st->process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
145
146 return 0;
147 }
148
stats_read_memory_stat(bool per_app_memcg,int pid,uid_t uid,int64_t rss_bytes,int64_t swap_bytes)149 struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t uid,
150 int64_t rss_bytes, int64_t swap_bytes) {
151 static struct memory_stat mem_st = {};
152 if (!enable_stats_log) {
153 return NULL;
154 }
155
156 if (per_app_memcg) {
157 if (memory_stat_from_cgroup(&mem_st, pid, uid) == 0) {
158 return &mem_st;
159 }
160 } else {
161 if (memory_stat_from_procfs(&mem_st, pid) == 0) {
162 mem_st.rss_in_bytes = rss_bytes;
163 mem_st.swap_in_bytes = swap_bytes;
164 return &mem_st;
165 }
166 }
167
168 return NULL;
169 }
170
proc_insert(struct proc * procp)171 static void proc_insert(struct proc* procp) {
172 if (!pidhash) {
173 pidhash = static_cast<struct proc**>(calloc(PIDHASH_SZ, sizeof(*pidhash)));
174 }
175
176 int hval = pid_hashfn(procp->pid);
177 procp->pidhash_next = pidhash[hval];
178 pidhash[hval] = procp;
179 }
180
stats_remove_taskname(int pid)181 void stats_remove_taskname(int pid) {
182 if (!enable_stats_log || !pidhash) {
183 return;
184 }
185
186 int hval = pid_hashfn(pid);
187 struct proc* procp;
188 struct proc* prevp;
189
190 for (procp = pidhash[hval], prevp = NULL; procp && procp->pid != pid;
191 procp = procp->pidhash_next)
192 prevp = procp;
193
194 if (!procp)
195 return;
196
197 if (!prevp)
198 pidhash[hval] = procp->pidhash_next;
199 else
200 prevp->pidhash_next = procp->pidhash_next;
201
202 free(procp);
203 }
204
stats_store_taskname(int pid,const char * taskname)205 void stats_store_taskname(int pid, const char* taskname) {
206 if (!enable_stats_log || !taskname) {
207 return;
208 }
209
210 struct proc* procp = pid_lookup(pid);
211 if (procp != NULL) {
212 if (strcmp(procp->taskname, taskname) == 0) {
213 return;
214 }
215 stats_remove_taskname(pid);
216 }
217 procp = static_cast<struct proc*>(malloc(sizeof(struct proc)));
218 procp->pid = pid;
219 strncpy(procp->taskname, taskname, MAX_TASKNAME_LEN - 1);
220 procp->taskname[MAX_TASKNAME_LEN - 1] = '\0';
221 proc_insert(procp);
222 }
223
stats_purge_tasknames()224 void stats_purge_tasknames() {
225 if (!enable_stats_log || !pidhash) {
226 return;
227 }
228
229 struct proc* procp;
230 struct proc* next;
231 int i;
232 for (i = 0; i < PIDHASH_SZ; i++) {
233 procp = pidhash[i];
234 while (procp) {
235 next = procp->pidhash_next;
236 free(procp);
237 procp = next;
238 }
239 }
240 memset(pidhash, 0, PIDHASH_SZ * sizeof(*pidhash));
241 }
242
stats_get_task_name(int pid)243 const char* stats_get_task_name(int pid) {
244 struct proc* proc = pid_lookup(pid);
245 return proc ? proc->taskname : NULL;
246 }
247
248 /**
249 * Writes int32 in a machine independent way
250 * https://docs.oracle.com/javase/7/docs/api/java/io/DataOutput.html#writeInt(int)
251 */
pack_int32(LMK_KILL_OCCURRED_PACKET packet,size_t index,int32_t value)252 static inline size_t pack_int32(LMK_KILL_OCCURRED_PACKET packet,
253 size_t index,
254 int32_t value) {
255 int32_t* int_buffer = (int32_t*)(packet + index);
256
257 *int_buffer = htonl(value);
258
259 return index + sizeof(int32_t);
260 }
261
262 /**
263 * Writes int64 in a machine independent way
264 * https://docs.oracle.com/javase/7/docs/api/java/io/DataOutput.html#writeLong(long)
265 */
pack_int64(LMK_KILL_OCCURRED_PACKET packet,size_t index,int64_t value)266 static inline size_t pack_int64(LMK_KILL_OCCURRED_PACKET packet,
267 size_t index,
268 int64_t value) {
269 int64_t* int64_buffer = (int64_t*)(packet + index);
270
271 *int64_buffer = htonq(value);
272
273 return index + sizeof(int64_t);
274 }
275
276 /**
277 * Writes ANSI string in a machine independent way
278 * https://docs.oracle.com/javase/7/docs/api/java/io/DataOutput.html#writeShort(int)
279 * 2 bytes str len following n chars
280 * to be read on the Java side with
281 * https://docs.oracle.com/javase/7/docs/api/java/io/DataInput.html#readUTF()
282 * Truncates the value string & packs up to MAX_TASKNAME_LEN - 1 chars
283 */
pack_string(LMK_KILL_OCCURRED_PACKET packet,size_t index,const char * value)284 static inline size_t pack_string(LMK_KILL_OCCURRED_PACKET packet,
285 size_t index,
286 const char* value) {
287 const size_t len_proc_name = MIN(strlen(value), MAX_TASKNAME_LEN - 1);
288 int16_t* short_buffer = (int16_t*)(packet + index);
289 *short_buffer = htons((int16_t)len_proc_name);
290
291 char* byte_buffer = (char*)(short_buffer + 1);
292 strncpy(byte_buffer, value, MAX_TASKNAME_LEN - 1);
293 byte_buffer[MAX_TASKNAME_LEN - 1] = '\0';
294
295 return index + sizeof(int16_t) + len_proc_name + 1;
296 }
297
lmkd_pack_set_kill_occurred(LMK_KILL_OCCURRED_PACKET packet,struct kill_stat * kill_stat,struct memory_stat * mem_stat)298 size_t lmkd_pack_set_kill_occurred(LMK_KILL_OCCURRED_PACKET packet,
299 struct kill_stat *kill_stat,
300 struct memory_stat *mem_stat) {
301 BUILD_BUG_ON(sizeof(LMK_KILL_OCCURRED_PACKET) > LMKD_REPLY_MAX_SIZE);
302
303 if (!enable_stats_log) {
304 return 0;
305 }
306
307 int32_t index = 0;
308 index = pack_int32(packet, index, LMK_STAT_KILL_OCCURRED);
309
310 if (mem_stat) {
311 index = pack_int64(packet, index, mem_stat->pgfault);
312 index = pack_int64(packet, index, mem_stat->pgmajfault);
313 index = pack_int64(packet, index, mem_stat->rss_in_bytes);
314 index = pack_int64(packet, index, mem_stat->cache_in_bytes);
315 index = pack_int64(packet, index, mem_stat->swap_in_bytes);
316 index = pack_int64(packet, index, mem_stat->process_start_time_ns);
317 } else {
318 index = pack_int64(packet, index, -1);
319 index = pack_int64(packet, index, -1);
320 index = pack_int64(packet, index, -1);
321 index = pack_int64(packet, index, -1);
322 index = pack_int64(packet, index, -1);
323 index = pack_int64(packet, index, -1);
324 }
325
326 index = pack_int32(packet, index, kill_stat->uid);
327 index = pack_int32(packet, index, kill_stat->oom_score);
328 index = pack_int32(packet, index, kill_stat->min_oom_score);
329 index = pack_int32(packet, index, (int)kill_stat->free_mem_kb);
330 index = pack_int32(packet, index, (int)kill_stat->free_swap_kb);
331 index = pack_int32(packet, index, (int)kill_stat->kill_reason);
332 index = pack_int32(packet, index, kill_stat->thrashing);
333 index = pack_int32(packet, index, kill_stat->max_thrashing);
334
335 index = pack_string(packet, index, kill_stat->taskname);
336 return index;
337 }
338
lmkd_pack_set_state_changed(LMKD_CTRL_PACKET packet,enum lmk_state state)339 size_t lmkd_pack_set_state_changed(LMKD_CTRL_PACKET packet,
340 enum lmk_state state) {
341 if (!enable_stats_log) {
342 return 0;
343 }
344
345 packet[0] = htonl(LMK_STAT_STATE_CHANGED);
346 packet[1] = htonl(state);
347
348 return 2 * sizeof(int);
349 }
350
351 #endif /* LMKD_LOG_STATS */
352