blob: 10f7255582d5bdc82a52b34ebc80e6c235c3c89d [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 Salyzyn81b3eab2015-04-13 14:24:45 -070042char *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
Mark Salyzyn81b3eab2015-04-13 14:24:45 -070073 uidTable[log_id].add(e->getUid(), e);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070074
75 mSizesTotal[log_id] += size;
76 ++mElementsTotal[log_id];
Mark Salyzyn720f6d12015-03-16 08:26:05 -070077
78 if (!enable) {
79 return;
80 }
81
Mark Salyzyn81b3eab2015-04-13 14:24:45 -070082 pidTable.add(e->getPid(), e);
Mark Salyzyn34facab2014-02-06 14:48:50 -080083}
84
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070085void LogStatistics::subtract(LogBufferElement *e) {
86 log_id_t log_id = e->getLogId();
87 unsigned short size = e->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -080088 mSizes[log_id] -= size;
89 --mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070090
Mark Salyzyn81b3eab2015-04-13 14:24:45 -070091 uidTable[log_id].subtract(e->getUid(), e);
Mark Salyzyn34facab2014-02-06 14:48:50 -080092
Mark Salyzyn720f6d12015-03-16 08:26:05 -070093 if (!enable) {
94 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -080095 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070096
Mark Salyzyn81b3eab2015-04-13 14:24:45 -070097 pidTable.subtract(e->getPid(), e);
Mark Salyzyn34facab2014-02-06 14:48:50 -080098}
99
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700100// Atomically set an entry to drop
101// entry->setDropped(1) must follow this call, caller should do this explicitly.
102void LogStatistics::drop(LogBufferElement *e) {
103 log_id_t log_id = e->getLogId();
104 unsigned short size = e->getMsgLen();
105 mSizes[log_id] -= size;
106
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700107 uidTable[log_id].drop(e->getUid(), e);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700108
109 if (!enable) {
110 return;
111 }
112
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700113 pidTable.drop(e->getPid(), e);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700114}
115
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700116// caller must own and free character string
117char *LogStatistics::uidToName(uid_t uid) {
118 // Local hard coded favourites
119 if (uid == AID_LOGD) {
120 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800121 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700122
123 // Android hard coded
124 const struct android_id_info *info = android_ids;
125
126 for (size_t i = 0; i < android_id_count; ++i) {
127 if (info->aid == uid) {
128 return strdup(info->name);
129 }
130 ++info;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800131 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700132
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700133 // Parse /data/system/packages.list
134 char *name = android::uidToName(uid);
135 if (name) {
136 return name;
137 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700138
139 // report uid -> pid(s) -> pidToName if unique
140 ssize_t index = -1;
141 while ((index = pidTable.next(index)) != -1) {
142 const PidEntry &entry = pidTable.entryAt(index);
143
144 if (entry.getUid() == uid) {
145 const char *n = entry.getName();
146
147 if (n) {
148 if (!name) {
149 name = strdup(n);
150 } else if (strcmp(name, n)) {
151 free(name);
152 return NULL;
153 }
154 }
155 }
156 }
157
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700158 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700159 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800160}
161
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700162static void format_line(android::String8 &output,
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700163 android::String8 &name, android::String8 &size, android::String8 &pruned) {
164 static const size_t pruned_len = 6;
165 static const size_t total_len = 70 + pruned_len;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700166
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700167 ssize_t drop_len = std::max(pruned.length() + 1, pruned_len);
168 ssize_t size_len = std::max(size.length() + 1,
169 total_len - name.length() - drop_len - 1);
170
171 if (pruned.length()) {
172 output.appendFormat("%s%*s%*s\n", name.string(),
173 (int)size_len, size.string(),
174 (int)drop_len, pruned.string());
175 } else {
176 output.appendFormat("%s%*s\n", name.string(),
177 (int)size_len, size.string());
178 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800179}
180
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700181void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700182 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800183
184 if (*buf) {
Greg Hackmann239605e2014-04-06 21:25:58 -0700185 free(*buf);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800186 *buf = NULL;
187 }
188
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700189 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800190
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700191 android::String8 output("size/num");
192 size_t oldLength;
193 short spaces = 1;
194
195 log_id_for_each(id) {
196 if (!(logMask & (1 << id))) {
Mark Salyzync8a576c2014-04-04 16:35:59 -0700197 continue;
198 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700199 oldLength = output.length();
Mark Salyzync8a576c2014-04-04 16:35:59 -0700200 if (spaces < 0) {
201 spaces = 0;
202 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700203 output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
204 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800205 }
206
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700207 spaces = 4;
208 output.appendFormat("\nTotal");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800209
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700210 log_id_for_each(id) {
211 if (!(logMask & (1 << id))) {
212 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800213 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700214 oldLength = output.length();
215 if (spaces < 0) {
216 spaces = 0;
217 }
218 output.appendFormat("%*s%zu/%zu", spaces, "",
219 sizesTotal(id), elementsTotal(id));
220 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800221 }
222
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700223 spaces = 6;
224 output.appendFormat("\nNow");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800225
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700226 log_id_for_each(id) {
227 if (!(logMask & (1 << id))) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800228 continue;
229 }
230
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700231 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800232 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700233 oldLength = output.length();
Mark Salyzyne457b742014-02-19 17:18:31 -0800234 if (spaces < 0) {
235 spaces = 0;
236 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700237 output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
238 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800239 }
240 spaces += spaces_total;
241 }
242
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700243 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700244
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700245 // Chattiest by application (UID)
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700246 static const size_t maximum_sorted_entries = 32;
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700247 log_id_for_each(id) {
248 if (!(logMask & (1 << id))) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700249 continue;
250 }
251
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700252 bool headerPrinted = false;
253 std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
254 ssize_t index = -1;
255 while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700256 const UidEntry *entry = sorted[index];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700257 uid_t u = entry->getKey();
258 if ((uid != AID_ROOT) && (u != uid)) {
259 continue;
260 }
261
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700262 if (!headerPrinted) {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700263 output.appendFormat("\n\n");
264 android::String8 name("");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700265 if (uid == AID_ROOT) {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700266 name.appendFormat(
267 "Chattiest UIDs in %s log buffer:",
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700268 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700269 } else {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700270 name.appendFormat(
271 "Logging for your UID in %s log buffer:",
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700272 android_log_id_to_name(id));
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700273 }
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700274 android::String8 size("Size");
275 android::String8 pruned("Pruned");
Mark Salyzynae769232015-03-17 17:17:25 -0700276 if (!worstUidEnabledForLogid(id)) {
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700277 pruned.setTo("");
278 }
279 format_line(output, name, size, pruned);
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700280
281 name.setTo("UID PACKAGE");
282 size.setTo("BYTES");
283 pruned.setTo("LINES");
284 if (!worstUidEnabledForLogid(id)) {
285 pruned.setTo("");
286 }
287 format_line(output, name, size, pruned);
288
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700289 headerPrinted = true;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700290 }
291
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700292 android::String8 name("");
293 name.appendFormat("%u", u);
294 char *n = uidToName(u);
295 if (n) {
296 name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
297 free(n);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700298 }
299
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700300 android::String8 size("");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700301 size.appendFormat("%zu", entry->getSizes());
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700302
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700303 android::String8 pruned("");
304 size_t dropped = entry->getDropped();
305 if (dropped) {
306 pruned.appendFormat("%zu", dropped);
307 }
308
309 format_line(output, name, size, pruned);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700310 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700311 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700312
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700313 if (enable) {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700314 // Pid table
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700315 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) {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700326 output.appendFormat("\n\n");
327 android::String8 name("");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700328 if (uid == AID_ROOT) {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700329 name.appendFormat("Chattiest PIDs:");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700330 } else {
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700331 name.appendFormat("Logging for this PID:");
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700332 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700333 android::String8 size("Size");
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700334 android::String8 pruned("Pruned");
335 format_line(output, name, size, pruned);
Mark Salyzyn5720d2c2015-04-21 07:43:16 -0700336
337 name.setTo(" PID/UID COMMAND LINE");
338 size.setTo("BYTES");
339 pruned.setTo("LINES");
340 format_line(output, name, size, pruned);
341
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700342 headerPrinted = true;
343 }
344
345 android::String8 name("");
346 name.appendFormat("%5u/%u", entry->getKey(), u);
347 const char *n = entry->getName();
348 if (n) {
349 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
350 } else {
351 char *un = uidToName(u);
352 if (un) {
353 name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
354 free(un);
355 }
356 }
357
358 android::String8 size("");
359 size.appendFormat("%zu", entry->getSizes());
360
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700361 android::String8 pruned("");
362 size_t dropped = entry->getDropped();
363 if (dropped) {
364 pruned.appendFormat("%zu", dropped);
365 }
366
367 format_line(output, name, size, pruned);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700368 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700369 }
370
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700371 *buf = strdup(output.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800372}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700373
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700374namespace android {
375
376uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700377 char buffer[512];
378 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
379 FILE *fp = fopen(buffer, "r");
380 if (fp) {
381 while (fgets(buffer, sizeof(buffer), fp)) {
382 int uid;
Mark Salyzync32afdf2015-04-14 13:07:29 -0700383 if (sscanf(buffer, "Uid: %d", &uid) == 1) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700384 fclose(fp);
385 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700386 }
387 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700388 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700389 }
Mark Salyzyne3aeeee2015-03-17 07:56:32 -0700390 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700391}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700392
393}
394
395uid_t LogStatistics::pidToUid(pid_t pid) {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700396 return pidTable.entryAt(pidTable.add(pid)).getUid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700397}
398
399// caller must free character string
400char *LogStatistics::pidToName(pid_t pid) {
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700401 const char *name = pidTable.entryAt(pidTable.add(pid)).getName();
402 if (!name) {
403 return NULL;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700404 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700405 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700406}