blob: 6e5454a3705c5d0d60926d0b3c671836e2bac39c [file] [log] [blame]
Mark Salyzyn34facab2014-02-06 14:48:50 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
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
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070017#include <algorithm> // std::max
Mark Salyzyn9a038632014-04-07 07:05:40 -070018#include <fcntl.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070019#include <stdio.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070020#include <string.h>
21#include <unistd.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080022
23#include <log/logger.h>
24#include <private/android_filesystem_config.h>
25#include <utils/String8.h>
26
27#include "LogStatistics.h"
28
Mark Salyzyn720f6d12015-03-16 08:26:05 -070029LogStatistics::LogStatistics()
30 : enable(false) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070031 log_id_for_each(id) {
32 mSizes[id] = 0;
33 mElements[id] = 0;
34 mSizesTotal[id] = 0;
35 mElementsTotal[id] = 0;
Mark Salyzyn34facab2014-02-06 14:48:50 -080036 }
37}
38
Mark Salyzyn720f6d12015-03-16 08:26:05 -070039namespace android {
40
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070041// caller must own and free character string
Mark Salyzyn720f6d12015-03-16 08:26:05 -070042static char *pidToName(pid_t pid) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070043 char *retval = NULL;
Mark Salyzyndf5aa612014-09-21 14:22:18 -070044 if (pid == 0) { // special case from auditd for kernel
45 retval = strdup("logd.auditd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070046 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070047 char buffer[512];
48 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
49 int fd = open(buffer, O_RDONLY);
50 if (fd >= 0) {
51 ssize_t ret = read(fd, buffer, sizeof(buffer));
52 if (ret > 0) {
53 buffer[sizeof(buffer)-1] = '\0';
54 // frameworks intermediate state
55 if (strcmp(buffer, "<pre-initialized>")) {
56 retval = strdup(buffer);
57 }
58 }
59 close(fd);
60 }
61 }
62 return retval;
63}
64
Mark Salyzyn720f6d12015-03-16 08:26:05 -070065}
66
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070067void LogStatistics::add(LogBufferElement *e) {
68 log_id_t log_id = e->getLogId();
69 unsigned short size = e->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -080070 mSizes[log_id] += size;
71 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070072
73 uid_t uid = e->getUid();
74 android::hash_t hash = android::hash_type(uid);
75 uidTable_t &table = uidTable[log_id];
76 ssize_t index = table.find(-1, hash, uid);
77 if (index == -1) {
78 UidEntry initEntry(uid);
79 initEntry.add(size);
80 table.add(hash, initEntry);
81 } else {
82 UidEntry &entry = table.editEntryAt(index);
83 entry.add(size);
Mark Salyzynf5fc5092014-09-21 14:22:18 -070084 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070085
86 mSizesTotal[log_id] += size;
87 ++mElementsTotal[log_id];
Mark Salyzyn720f6d12015-03-16 08:26:05 -070088
89 if (!enable) {
90 return;
91 }
92
93 pid_t pid = e->getPid();
94 hash = android::hash_type(pid);
95 index = pidTable.find(-1, hash, pid);
96 if (index == -1) {
97 PidEntry initEntry(pid, uid, android::pidToName(pid));
98 initEntry.add(size);
99 pidTable.add(hash, initEntry);
100 } else {
101 PidEntry &entry = pidTable.editEntryAt(index);
102 if (entry.getUid() != uid) {
103 entry.setUid(uid);
104 entry.setName(android::pidToName(pid));
105 } else if (!entry.getName()) {
106 char *name = android::pidToName(pid);
107 if (name) {
108 entry.setName(name);
109 }
110 }
111 entry.add(size);
112 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800113}
114
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700115void LogStatistics::subtract(LogBufferElement *e) {
116 log_id_t log_id = e->getLogId();
117 unsigned short size = e->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800118 mSizes[log_id] -= size;
119 --mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700120
121 uid_t uid = e->getUid();
122 android::hash_t hash = android::hash_type(uid);
123 uidTable_t &table = uidTable[log_id];
124 ssize_t index = table.find(-1, hash, uid);
125 if (index != -1) {
126 UidEntry &entry = table.editEntryAt(index);
127 if (entry.subtract(size)) {
128 table.removeAt(index);
129 }
Mark Salyzynf5fc5092014-09-21 14:22:18 -0700130 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800131
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700132 if (!enable) {
133 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800134 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700135
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700136 pid_t pid = e->getPid();
137 hash = android::hash_type(pid);
138 index = pidTable.find(-1, hash, pid);
139 if (index != -1) {
140 PidEntry &entry = pidTable.editEntryAt(index);
141 if (entry.subtract(size)) {
142 pidTable.removeAt(index);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700143 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800144 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800145}
146
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700147// caller must own and free character string
148char *LogStatistics::uidToName(uid_t uid) {
149 // Local hard coded favourites
150 if (uid == AID_LOGD) {
151 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800152 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700153
154 // Android hard coded
155 const struct android_id_info *info = android_ids;
156
157 for (size_t i = 0; i < android_id_count; ++i) {
158 if (info->aid == uid) {
159 return strdup(info->name);
160 }
161 ++info;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800162 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700163
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700164 char *name = NULL;
165
166 // report uid -> pid(s) -> pidToName if unique
167 ssize_t index = -1;
168 while ((index = pidTable.next(index)) != -1) {
169 const PidEntry &entry = pidTable.entryAt(index);
170
171 if (entry.getUid() == uid) {
172 const char *n = entry.getName();
173
174 if (n) {
175 if (!name) {
176 name = strdup(n);
177 } else if (strcmp(name, n)) {
178 free(name);
179 return NULL;
180 }
181 }
182 }
183 }
184
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700185 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700186 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800187}
188
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700189static void format_line(android::String8 &output,
190 android::String8 &name, android::String8 &size) {
191 static const size_t total_len = 70;
192
193 output.appendFormat("%s%*s\n", name.string(),
Mark Salyzyn317843d2015-03-20 13:44:53 -0700194 (int)std::max(total_len - name.length() - 1, size.length() + 1),
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700195 size.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800196}
197
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700198void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700199 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800200
201 if (*buf) {
Greg Hackmann239605e2014-04-06 21:25:58 -0700202 free(*buf);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800203 *buf = NULL;
204 }
205
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700206 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800207
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700208 android::String8 output("size/num");
209 size_t oldLength;
210 short spaces = 1;
211
212 log_id_for_each(id) {
213 if (!(logMask & (1 << id))) {
Mark Salyzync8a576c2014-04-04 16:35:59 -0700214 continue;
215 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700216 oldLength = output.length();
Mark Salyzync8a576c2014-04-04 16:35:59 -0700217 if (spaces < 0) {
218 spaces = 0;
219 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700220 output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
221 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800222 }
223
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700224 spaces = 4;
225 output.appendFormat("\nTotal");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800226
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700227 log_id_for_each(id) {
228 if (!(logMask & (1 << id))) {
229 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800230 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700231 oldLength = output.length();
232 if (spaces < 0) {
233 spaces = 0;
234 }
235 output.appendFormat("%*s%zu/%zu", spaces, "",
236 sizesTotal(id), elementsTotal(id));
237 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800238 }
239
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700240 spaces = 6;
241 output.appendFormat("\nNow");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800242
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700243 log_id_for_each(id) {
244 if (!(logMask & (1 << id))) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800245 continue;
246 }
247
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700248 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800249 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700250 oldLength = output.length();
Mark Salyzyne457b742014-02-19 17:18:31 -0800251 if (spaces < 0) {
252 spaces = 0;
253 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700254 output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
255 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800256 }
257 spaces += spaces_total;
258 }
259
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700260 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700261
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700262 // Chattiest by application (UID)
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700263 static const size_t maximum_sorted_entries = 32;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700264 log_id_for_each(id) {
265 if (!(logMask & (1 << id))) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700266 continue;
267 }
268
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700269 bool headerPrinted = false;
270 std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
271 ssize_t index = -1;
272 while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700273 const UidEntry *entry = sorted[index];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700274 uid_t u = entry->getKey();
275 if ((uid != AID_ROOT) && (u != uid)) {
276 continue;
277 }
278
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700279 if (!headerPrinted) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700280 if (uid == AID_ROOT) {
281 output.appendFormat(
282 "\n\nChattiest UIDs in %s:\n",
283 android_log_id_to_name(id));
284 android::String8 name("UID");
285 android::String8 size("Size");
286 format_line(output, name, size);
287 } else {
288 output.appendFormat(
289 "\n\nLogging for your UID in %s:\n",
290 android_log_id_to_name(id));
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700291 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700292 headerPrinted = true;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700293 }
294
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700295 android::String8 name("");
296 name.appendFormat("%u", u);
297 char *n = uidToName(u);
298 if (n) {
299 name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
300 free(n);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700301 }
302
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700303 android::String8 size("");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700304 size.appendFormat("%zu", entry->getSizes());
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700305
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700306 format_line(output, name, size);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700307 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700308 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700309
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700310 if (enable) {
311 bool headerPrinted = false;
312 std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
313 ssize_t index = -1;
314 while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
315 const PidEntry *entry = sorted[index];
316 uid_t u = entry->getUid();
317 if ((uid != AID_ROOT) && (u != uid)) {
318 continue;
319 }
320
321 if (!headerPrinted) {
322 if (uid == AID_ROOT) {
323 output.appendFormat("\n\nChattiest PIDs:\n");
324 } else {
325 output.appendFormat("\n\nLogging for this PID:\n");
326 }
327 android::String8 name(" PID/UID");
328 android::String8 size("Size");
329 android::String8 pruned("Pruned");
330 format_line(output, name, size, pruned);
331 headerPrinted = true;
332 }
333
334 android::String8 name("");
335 name.appendFormat("%5u/%u", entry->getKey(), u);
336 const char *n = entry->getName();
337 if (n) {
338 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
339 } else {
340 char *un = uidToName(u);
341 if (un) {
342 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
343 free(un);
344 }
345 }
346
347 android::String8 size("");
348 size.appendFormat("%zu", entry->getSizes());
349
350 format_line(output, name, size);
351 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700352 }
353
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700354 *buf = strdup(output.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800355}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700356
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700357namespace android {
358
359uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700360 char buffer[512];
361 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
362 FILE *fp = fopen(buffer, "r");
363 if (fp) {
364 while (fgets(buffer, sizeof(buffer), fp)) {
365 int uid;
366 if (sscanf(buffer, "Groups: %d", &uid) == 1) {
367 fclose(fp);
368 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700369 }
370 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700371 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700372 }
373 return getuid(); // associate this with the logger
374}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700375
376}
377
378uid_t LogStatistics::pidToUid(pid_t pid) {
379 uid_t uid;
380 android::hash_t hash = android::hash_type(pid);
381 ssize_t index = pidTable.find(-1, hash, pid);
382 if (index == -1) {
383 uid = android::pidToUid(pid);
384 PidEntry initEntry(pid, uid, android::pidToName(pid));
385 pidTable.add(hash, initEntry);
386 } else {
387 PidEntry &entry = pidTable.editEntryAt(index);
388 if (!entry.getName()) {
389 char *name = android::pidToName(pid);
390 if (name) {
391 entry.setName(name);
392 }
393 }
394 uid = entry.getUid();
395 }
396 return uid;
397}
398
399// caller must free character string
400char *LogStatistics::pidToName(pid_t pid) {
401 char *name;
402
403 android::hash_t hash = android::hash_type(pid);
404 ssize_t index = pidTable.find(-1, hash, pid);
405 if (index == -1) {
406 name = android::pidToName(pid);
407 PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
408 pidTable.add(hash, initEntry);
409 } else {
410 PidEntry &entry = pidTable.editEntryAt(index);
411 const char *n = entry.getName();
412 if (n) {
413 name = strdup(n);
414 } else {
415 name = android::pidToName(pid);
416 if (name) {
417 entry.setName(strdup(name));
418 }
419 }
420 }
421
422 return name;
423}