blob: 6bb0b40baf9485e9f62b5f5ea2dd2e345ba685f4 [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>
20#include <stdlib.h>
21#include <string.h>
22#include <unistd.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080023
24#include <log/logger.h>
25#include <private/android_filesystem_config.h>
26#include <utils/String8.h>
27
28#include "LogStatistics.h"
29
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070030LogStatistics::LogStatistics() {
31 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 Salyzyn97c1c2b2015-03-10 13:51:35 -070039// caller must own and free character string
40char *LogStatistics::pidToName(pid_t pid) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070041 char *retval = NULL;
Mark Salyzyndf5aa612014-09-21 14:22:18 -070042 if (pid == 0) { // special case from auditd for kernel
43 retval = strdup("logd.auditd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070044 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070045 char buffer[512];
46 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
47 int fd = open(buffer, O_RDONLY);
48 if (fd >= 0) {
49 ssize_t ret = read(fd, buffer, sizeof(buffer));
50 if (ret > 0) {
51 buffer[sizeof(buffer)-1] = '\0';
52 // frameworks intermediate state
53 if (strcmp(buffer, "<pre-initialized>")) {
54 retval = strdup(buffer);
55 }
56 }
57 close(fd);
58 }
59 }
60 return retval;
61}
62
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070063void LogStatistics::add(LogBufferElement *e) {
64 log_id_t log_id = e->getLogId();
65 unsigned short size = e->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -080066 mSizes[log_id] += size;
67 ++mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070068
69 uid_t uid = e->getUid();
70 android::hash_t hash = android::hash_type(uid);
71 uidTable_t &table = uidTable[log_id];
72 ssize_t index = table.find(-1, hash, uid);
73 if (index == -1) {
74 UidEntry initEntry(uid);
75 initEntry.add(size);
76 table.add(hash, initEntry);
77 } else {
78 UidEntry &entry = table.editEntryAt(index);
79 entry.add(size);
Mark Salyzynf5fc5092014-09-21 14:22:18 -070080 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070081
82 mSizesTotal[log_id] += size;
83 ++mElementsTotal[log_id];
Mark Salyzyn34facab2014-02-06 14:48:50 -080084}
85
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070086void LogStatistics::subtract(LogBufferElement *e) {
87 log_id_t log_id = e->getLogId();
88 unsigned short size = e->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -080089 mSizes[log_id] -= size;
90 --mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070091
92 uid_t uid = e->getUid();
93 android::hash_t hash = android::hash_type(uid);
94 uidTable_t &table = uidTable[log_id];
95 ssize_t index = table.find(-1, hash, uid);
96 if (index != -1) {
97 UidEntry &entry = table.editEntryAt(index);
98 if (entry.subtract(size)) {
99 table.removeAt(index);
100 }
Mark Salyzynf5fc5092014-09-21 14:22:18 -0700101 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800102}
103
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700104// caller must own and delete UidEntry array
105const UidEntry **LogStatistics::sort(size_t n, log_id id) {
106 if (!n) {
107 return NULL;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800108 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700109
110 const UidEntry **retval = new const UidEntry* [n];
111 memset(retval, 0, sizeof(*retval) * n);
112
113 uidTable_t &table = uidTable[id];
114 ssize_t index = -1;
115 while ((index = table.next(index)) >= 0) {
116 const UidEntry &entry = table.entryAt(index);
117 size_t s = entry.getSizes();
118 ssize_t i = n - 1;
119 while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0));
120 if (++i < (ssize_t)n) {
121 size_t b = n - i - 1;
122 if (b) {
123 memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
124 }
125 retval[i] = &entry;
126 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800127 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700128 return retval;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800129}
130
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700131// caller must own and free character string
132char *LogStatistics::uidToName(uid_t uid) {
133 // Local hard coded favourites
134 if (uid == AID_LOGD) {
135 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800136 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700137
138 // Android hard coded
139 const struct android_id_info *info = android_ids;
140
141 for (size_t i = 0; i < android_id_count; ++i) {
142 if (info->aid == uid) {
143 return strdup(info->name);
144 }
145 ++info;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800146 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700147
148 // No one
149 return NULL;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800150}
151
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700152static void format_line(android::String8 &output,
153 android::String8 &name, android::String8 &size) {
154 static const size_t total_len = 70;
155
156 output.appendFormat("%s%*s\n", name.string(),
Mark Salyzyn317843d2015-03-20 13:44:53 -0700157 (int)std::max(total_len - name.length() - 1, size.length() + 1),
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700158 size.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800159}
160
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700161void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700162 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800163
164 if (*buf) {
Greg Hackmann239605e2014-04-06 21:25:58 -0700165 free(*buf);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800166 *buf = NULL;
167 }
168
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700169 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800170
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700171 android::String8 output("size/num");
172 size_t oldLength;
173 short spaces = 1;
174
175 log_id_for_each(id) {
176 if (!(logMask & (1 << id))) {
Mark Salyzync8a576c2014-04-04 16:35:59 -0700177 continue;
178 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700179 oldLength = output.length();
Mark Salyzync8a576c2014-04-04 16:35:59 -0700180 if (spaces < 0) {
181 spaces = 0;
182 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700183 output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
184 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800185 }
186
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700187 spaces = 4;
188 output.appendFormat("\nTotal");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800189
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700190 log_id_for_each(id) {
191 if (!(logMask & (1 << id))) {
192 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800193 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700194 oldLength = output.length();
195 if (spaces < 0) {
196 spaces = 0;
197 }
198 output.appendFormat("%*s%zu/%zu", spaces, "",
199 sizesTotal(id), elementsTotal(id));
200 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800201 }
202
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700203 spaces = 6;
204 output.appendFormat("\nNow");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800205
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700206 log_id_for_each(id) {
207 if (!(logMask & (1 << id))) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800208 continue;
209 }
210
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700211 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800212 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700213 oldLength = output.length();
Mark Salyzyne457b742014-02-19 17:18:31 -0800214 if (spaces < 0) {
215 spaces = 0;
216 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700217 output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
218 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800219 }
220 spaces += spaces_total;
221 }
222
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700223 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700224
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700225 // Chattiest by application (UID)
226 log_id_for_each(id) {
227 if (!(logMask & (1 << id))) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700228 continue;
229 }
230
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700231 static const size_t maximum_sorted_entries = 32;
232 const UidEntry **sorted = sort(maximum_sorted_entries, id);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700233
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700234 if (!sorted) {
235 continue;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700236 }
237
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700238 bool print = false;
239 for(size_t index = 0; index < maximum_sorted_entries; ++index) {
240 const UidEntry *entry = sorted[index];
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700241
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700242 if (!entry) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700243 break;
244 }
245
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700246 size_t sizes = entry->getSizes();
247 if (sizes < (65536/100)) {
248 break;
249 }
250
251 uid_t u = entry->getKey();
252 if ((uid != AID_ROOT) && (u != uid)) {
253 continue;
254 }
255
256 if (!print) {
257 if (uid == AID_ROOT) {
258 output.appendFormat(
259 "\n\nChattiest UIDs in %s:\n",
260 android_log_id_to_name(id));
261 android::String8 name("UID");
262 android::String8 size("Size");
263 format_line(output, name, size);
264 } else {
265 output.appendFormat(
266 "\n\nLogging for your UID in %s:\n",
267 android_log_id_to_name(id));
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700268 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700269 print = true;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700270 }
271
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700272 android::String8 name("");
273 name.appendFormat("%u", u);
274 char *n = uidToName(u);
275 if (n) {
276 name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
277 free(n);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700278 }
279
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700280 android::String8 size("");
281 size.appendFormat("%zu", sizes);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700282
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700283 format_line(output, name, size);
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700284 }
285
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700286 delete [] sorted;
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700287 }
288
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700289 *buf = strdup(output.string());
Mark Salyzyn34facab2014-02-06 14:48:50 -0800290}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700291
292uid_t LogStatistics::pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700293 char buffer[512];
294 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
295 FILE *fp = fopen(buffer, "r");
296 if (fp) {
297 while (fgets(buffer, sizeof(buffer), fp)) {
298 int uid;
299 if (sscanf(buffer, "Groups: %d", &uid) == 1) {
300 fclose(fp);
301 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700302 }
303 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700304 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700305 }
Mark Salyzyne3aeeee2015-03-17 07:56:32 -0700306 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700307}