• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <lmkd.h>
36 #include <processgroup/processgroup.h>
37 
38 #ifdef LMKD_LOG_STATS
39 
40 #define STRINGIFY(x) STRINGIFY_INTERNAL(x)
41 #define STRINGIFY_INTERNAL(x) #x
42 
43 /**
44  * Used to make sure that the payload is always smaller than LMKD_REPLY_MAX_SIZE
45  */
46 #define BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2 * !!(cond)]))
47 
48 static bool enable_stats_log = property_get_bool("ro.lmk.log_stats", true);
49 
50 struct proc {
51     int pid;
52     char taskname[MAX_TASKNAME_LEN];
53     struct proc* pidhash_next;
54 };
55 
56 #define PIDHASH_SZ 1024
57 static struct proc** pidhash = NULL;
58 #define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
59 
pid_lookup(int pid)60 static struct proc* pid_lookup(int pid) {
61     struct proc* procp;
62 
63     if (!pidhash) return NULL;
64 
65     for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid; procp = procp->pidhash_next)
66         ;
67 
68     return procp;
69 }
70 
memory_stat_parse_line(const char * line,struct memory_stat * mem_st)71 static void memory_stat_parse_line(const char* line, struct memory_stat* mem_st) {
72     char key[MAX_TASKNAME_LEN + 1];
73     int64_t value;
74 
75     sscanf(line, "%" STRINGIFY(MAX_TASKNAME_LEN) "s  %" SCNd64 "", key, &value);
76 
77     if (strcmp(key, "total_") < 0) {
78         return;
79     }
80 
81     if (!strcmp(key, "total_pgfault"))
82         mem_st->pgfault = value;
83     else if (!strcmp(key, "total_pgmajfault"))
84         mem_st->pgmajfault = value;
85     else if (!strcmp(key, "total_rss"))
86         mem_st->rss_in_bytes = value;
87     else if (!strcmp(key, "total_cache"))
88         mem_st->cache_in_bytes = value;
89     else if (!strcmp(key, "total_swap"))
90         mem_st->swap_in_bytes = value;
91 }
92 
memory_stat_from_cgroup(struct memory_stat * mem_st,int pid,uid_t uid __unused)93 static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid __unused) {
94     std::string path;
95     if (!CgroupGetAttributePathForTask("MemStats", pid, &path)) {
96         ALOGE("Querying MemStats path failed");
97         return -1;
98     }
99 
100     FILE* fp = fopen(path.c_str(), "r");
101 
102     if (fp == NULL) {
103         return -1;
104     }
105 
106     char buf[LINE_MAX];
107     while (fgets(buf, LINE_MAX, fp) != NULL) {
108         memory_stat_parse_line(buf, mem_st);
109     }
110     fclose(fp);
111 
112     return 0;
113 }
114 
memory_stat_from_procfs(struct memory_stat * mem_st,int pid)115 static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) {
116     char path[PATH_MAX];
117     char buffer[PROC_STAT_BUFFER_SIZE];
118     int fd, ret;
119 
120     snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid);
121     if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) {
122         return -1;
123     }
124 
125     ret = read(fd, buffer, sizeof(buffer));
126     if (ret < 0) {
127         close(fd);
128         return -1;
129     }
130     close(fd);
131 
132     // field 10 is pgfault
133     // field 12 is pgmajfault
134     // field 22 is starttime
135     int64_t pgfault = 0, pgmajfault = 0, starttime = 0;
136     if (sscanf(buffer,
137                "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d "
138                "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d "
139                "%" SCNd64 "",
140                &pgfault, &pgmajfault, &starttime) != 3) {
141         return -1;
142     }
143     mem_st->pgfault = pgfault;
144     mem_st->pgmajfault = pgmajfault;
145     mem_st->process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK));
146 
147     return 0;
148 }
149 
stats_read_memory_stat(bool per_app_memcg,int pid,uid_t uid,int64_t rss_bytes,int64_t swap_bytes)150 struct memory_stat *stats_read_memory_stat(bool per_app_memcg, int pid, uid_t uid,
151                                            int64_t rss_bytes, int64_t swap_bytes) {
152     static struct memory_stat mem_st = {};
153     if (!enable_stats_log) {
154         return NULL;
155     }
156 
157     if (per_app_memcg) {
158         if (memory_stat_from_cgroup(&mem_st, pid, uid) == 0) {
159             return &mem_st;
160         }
161     }
162     if (memory_stat_from_procfs(&mem_st, pid) == 0) {
163         mem_st.rss_in_bytes = rss_bytes;
164         mem_st.swap_in_bytes = swap_bytes;
165         return &mem_st;
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 
339 #endif /* LMKD_LOG_STATS */
340