blob: 517135d9d6c79e2c3084553a4dd37fb05009f0ec [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 Salyzyn08739ba2015-03-16 08:26:05 -0700164 // Parse /data/system/packages.list
165 char *name = android::uidToName(uid);
166 if (name) {
167 return name;
168 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700169
170 // report uid -> pid(s) -> pidToName if unique
171 ssize_t index = -1;
172 while ((index = pidTable.next(index)) != -1) {
173 const PidEntry &entry = pidTable.entryAt(index);
174
175 if (entry.getUid() == uid) {
176 const char *n = entry.getName();
177
178 if (n) {
179 if (!name) {
180 name = strdup(n);
181 } else if (strcmp(name, n)) {
182 free(name);
183 return NULL;
184 }
185 }
186 }
187 }
188
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700189 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700190 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800191}
192
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700193static void format_line(android::String8 &output,
194 android::String8 &name, android::String8 &size) {
195 static const size_t total_len = 70;
196
197 output.appendFormat("%s%*s\n", name.string(),
Mark Salyzyn317843d2015-03-20 13:44:53 -0700198 (int)std::max(total_len - name.length() - 1, size.length() + 1),
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700199 size.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800200}
201
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700202void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700203 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800204
205 if (*buf) {
Greg Hackmann239605e2014-04-06 21:25:58 -0700206 free(*buf);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800207 *buf = NULL;
208 }
209
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700210 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800211
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700212 android::String8 output("size/num");
213 size_t oldLength;
214 short spaces = 1;
215
216 log_id_for_each(id) {
217 if (!(logMask & (1 << id))) {
Mark Salyzync8a576c2014-04-04 16:35:59 -0700218 continue;
219 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700220 oldLength = output.length();
Mark Salyzync8a576c2014-04-04 16:35:59 -0700221 if (spaces < 0) {
222 spaces = 0;
223 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700224 output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
225 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800226 }
227
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700228 spaces = 4;
229 output.appendFormat("\nTotal");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800230
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700231 log_id_for_each(id) {
232 if (!(logMask & (1 << id))) {
233 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800234 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700235 oldLength = output.length();
236 if (spaces < 0) {
237 spaces = 0;
238 }
239 output.appendFormat("%*s%zu/%zu", spaces, "",
240 sizesTotal(id), elementsTotal(id));
241 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800242 }
243
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700244 spaces = 6;
245 output.appendFormat("\nNow");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800246
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700247 log_id_for_each(id) {
248 if (!(logMask & (1 << id))) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800249 continue;
250 }
251
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700252 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800253 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700254 oldLength = output.length();
Mark Salyzyne457b742014-02-19 17:18:31 -0800255 if (spaces < 0) {
256 spaces = 0;
257 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700258 output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
259 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800260 }
261 spaces += spaces_total;
262 }
263
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700264 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700265
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700266 // Chattiest by application (UID)
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700267 static const size_t maximum_sorted_entries = 32;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700268 log_id_for_each(id) {
269 if (!(logMask & (1 << id))) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700270 continue;
271 }
272
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700273 bool headerPrinted = false;
274 std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
275 ssize_t index = -1;
276 while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700277 const UidEntry *entry = sorted[index];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700278 uid_t u = entry->getKey();
279 if ((uid != AID_ROOT) && (u != uid)) {
280 continue;
281 }
282
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700283 if (!headerPrinted) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700284 if (uid == AID_ROOT) {
285 output.appendFormat(
286 "\n\nChattiest UIDs in %s:\n",
287 android_log_id_to_name(id));
288 android::String8 name("UID");
289 android::String8 size("Size");
290 format_line(output, name, size);
291 } else {
292 output.appendFormat(
293 "\n\nLogging for your UID in %s:\n",
294 android_log_id_to_name(id));
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700295 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700296 headerPrinted = true;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700297 }
298
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700299 android::String8 name("");
300 name.appendFormat("%u", u);
301 char *n = uidToName(u);
302 if (n) {
303 name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
304 free(n);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700305 }
306
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700307 android::String8 size("");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700308 size.appendFormat("%zu", entry->getSizes());
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700309
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700310 format_line(output, name, size);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700311 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700312 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700313
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700314 if (enable) {
315 bool headerPrinted = false;
316 std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
317 ssize_t index = -1;
318 while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
319 const PidEntry *entry = sorted[index];
320 uid_t u = entry->getUid();
321 if ((uid != AID_ROOT) && (u != uid)) {
322 continue;
323 }
324
325 if (!headerPrinted) {
326 if (uid == AID_ROOT) {
327 output.appendFormat("\n\nChattiest PIDs:\n");
328 } else {
329 output.appendFormat("\n\nLogging for this PID:\n");
330 }
331 android::String8 name(" PID/UID");
332 android::String8 size("Size");
333 android::String8 pruned("Pruned");
334 format_line(output, name, size, pruned);
335 headerPrinted = true;
336 }
337
338 android::String8 name("");
339 name.appendFormat("%5u/%u", entry->getKey(), u);
340 const char *n = entry->getName();
341 if (n) {
342 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
343 } else {
344 char *un = uidToName(u);
345 if (un) {
346 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
347 free(un);
348 }
349 }
350
351 android::String8 size("");
352 size.appendFormat("%zu", entry->getSizes());
353
354 format_line(output, name, size);
355 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700356 }
357
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700358 *buf = strdup(output.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800359}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700360
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700361namespace android {
362
363uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700364 char buffer[512];
365 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
366 FILE *fp = fopen(buffer, "r");
367 if (fp) {
368 while (fgets(buffer, sizeof(buffer), fp)) {
369 int uid;
370 if (sscanf(buffer, "Groups: %d", &uid) == 1) {
371 fclose(fp);
372 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700373 }
374 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700375 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700376 }
377 return getuid(); // associate this with the logger
378}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700379
380}
381
382uid_t LogStatistics::pidToUid(pid_t pid) {
383 uid_t uid;
384 android::hash_t hash = android::hash_type(pid);
385 ssize_t index = pidTable.find(-1, hash, pid);
386 if (index == -1) {
387 uid = android::pidToUid(pid);
388 PidEntry initEntry(pid, uid, android::pidToName(pid));
389 pidTable.add(hash, initEntry);
390 } else {
391 PidEntry &entry = pidTable.editEntryAt(index);
392 if (!entry.getName()) {
393 char *name = android::pidToName(pid);
394 if (name) {
395 entry.setName(name);
396 }
397 }
398 uid = entry.getUid();
399 }
400 return uid;
401}
402
403// caller must free character string
404char *LogStatistics::pidToName(pid_t pid) {
405 char *name;
406
407 android::hash_t hash = android::hash_type(pid);
408 ssize_t index = pidTable.find(-1, hash, pid);
409 if (index == -1) {
410 name = android::pidToName(pid);
411 PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
412 pidTable.add(hash, initEntry);
413 } else {
414 PidEntry &entry = pidTable.editEntryAt(index);
415 const char *n = entry.getName();
416 if (n) {
417 name = strdup(n);
418 } else {
419 name = android::pidToName(pid);
420 if (name) {
421 entry.setName(strdup(name));
422 }
423 }
424 }
425
426 return name;
427}