blob: c3b10ad3617647422d51b400ec12e74cac09fc16 [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 Salyzyn9a038632014-04-07 07:05:40 -070017#include <fcntl.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070018#include <stdio.h>
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070019#include <string.h>
20#include <unistd.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080021
22#include <log/logger.h>
Mark Salyzyn34facab2014-02-06 14:48:50 -080023
24#include "LogStatistics.h"
25
Mark Salyzyn77187782015-05-12 15:21:31 -070026LogStatistics::LogStatistics() : enable(false) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070027 log_id_for_each(id) {
28 mSizes[id] = 0;
29 mElements[id] = 0;
30 mSizesTotal[id] = 0;
31 mElementsTotal[id] = 0;
Mark Salyzyn34facab2014-02-06 14:48:50 -080032 }
33}
34
Mark Salyzyn720f6d12015-03-16 08:26:05 -070035namespace android {
36
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070037// caller must own and free character string
Mark Salyzyn81b3eab2015-04-13 14:24:45 -070038char *pidToName(pid_t pid) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070039 char *retval = NULL;
Mark Salyzynae4d9282014-10-15 08:49:39 -070040 if (pid == 0) { // special case from auditd/klogd for kernel
41 retval = strdup("logd");
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070042 } else {
Mark Salyzyn9a038632014-04-07 07:05:40 -070043 char buffer[512];
44 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
45 int fd = open(buffer, O_RDONLY);
46 if (fd >= 0) {
47 ssize_t ret = read(fd, buffer, sizeof(buffer));
48 if (ret > 0) {
49 buffer[sizeof(buffer)-1] = '\0';
50 // frameworks intermediate state
Mark Salyzynddda2122015-10-02 09:22:52 -070051 if (fast<strcmp>(buffer, "<pre-initialized>")) {
Mark Salyzyn9a038632014-04-07 07:05:40 -070052 retval = strdup(buffer);
53 }
54 }
55 close(fd);
56 }
57 }
58 return retval;
59}
60
Mark Salyzyn720f6d12015-03-16 08:26:05 -070061}
62
Mark Salyzyn758058f2015-08-21 16:44:30 -070063void LogStatistics::add(LogBufferElement *element) {
64 log_id_t log_id = element->getLogId();
65 unsigned short size = element->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
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070069 mSizesTotal[log_id] += size;
70 ++mElementsTotal[log_id];
Mark Salyzyn720f6d12015-03-16 08:26:05 -070071
Mark Salyzynae4d9282014-10-15 08:49:39 -070072 if (log_id == LOG_ID_KERNEL) {
73 return;
74 }
75
Mark Salyzyn758058f2015-08-21 16:44:30 -070076 uidTable[log_id].add(element->getUid(), element);
Mark Salyzynae4d9282014-10-15 08:49:39 -070077
Mark Salyzyn720f6d12015-03-16 08:26:05 -070078 if (!enable) {
79 return;
80 }
81
Mark Salyzyn758058f2015-08-21 16:44:30 -070082 pidTable.add(element->getPid(), element);
83 tidTable.add(element->getTid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -070084
Mark Salyzyn758058f2015-08-21 16:44:30 -070085 uint32_t tag = element->getTag();
Mark Salyzyn344bff42015-04-13 14:24:45 -070086 if (tag) {
Mark Salyzyn758058f2015-08-21 16:44:30 -070087 tagTable.add(tag, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -070088 }
Mark Salyzyn34facab2014-02-06 14:48:50 -080089}
90
Mark Salyzyn758058f2015-08-21 16:44:30 -070091void LogStatistics::subtract(LogBufferElement *element) {
92 log_id_t log_id = element->getLogId();
93 unsigned short size = element->getMsgLen();
Mark Salyzyn34facab2014-02-06 14:48:50 -080094 mSizes[log_id] -= size;
95 --mElements[log_id];
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -070096
Mark Salyzynae4d9282014-10-15 08:49:39 -070097 if (log_id == LOG_ID_KERNEL) {
98 return;
99 }
100
Mark Salyzyn758058f2015-08-21 16:44:30 -0700101 uidTable[log_id].subtract(element->getUid(), element);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800102
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700103 if (!enable) {
104 return;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800105 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700106
Mark Salyzyn758058f2015-08-21 16:44:30 -0700107 pidTable.subtract(element->getPid(), element);
108 tidTable.subtract(element->getTid(), element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700109
Mark Salyzyn758058f2015-08-21 16:44:30 -0700110 uint32_t tag = element->getTag();
Mark Salyzyn344bff42015-04-13 14:24:45 -0700111 if (tag) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700112 tagTable.subtract(tag, element);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700113 }
Mark Salyzyn34facab2014-02-06 14:48:50 -0800114}
115
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700116// Atomically set an entry to drop
117// entry->setDropped(1) must follow this call, caller should do this explicitly.
Mark Salyzyn758058f2015-08-21 16:44:30 -0700118void LogStatistics::drop(LogBufferElement *element) {
119 log_id_t log_id = element->getLogId();
120 unsigned short size = element->getMsgLen();
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700121 mSizes[log_id] -= size;
122
Mark Salyzyn758058f2015-08-21 16:44:30 -0700123 uidTable[log_id].drop(element->getUid(), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700124
125 if (!enable) {
126 return;
127 }
128
Mark Salyzyn758058f2015-08-21 16:44:30 -0700129 pidTable.drop(element->getPid(), element);
130 tidTable.drop(element->getTid(), element);
Mark Salyzynab0dcf62015-03-16 12:04:09 -0700131}
132
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700133// caller must own and free character string
Mark Salyzyn758058f2015-08-21 16:44:30 -0700134const char *LogStatistics::uidToName(uid_t uid) const {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700135 // Local hard coded favourites
136 if (uid == AID_LOGD) {
137 return strdup("auditd");
Mark Salyzyn34facab2014-02-06 14:48:50 -0800138 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700139
140 // Android hard coded
141 const struct android_id_info *info = android_ids;
142
143 for (size_t i = 0; i < android_id_count; ++i) {
144 if (info->aid == uid) {
145 return strdup(info->name);
146 }
147 ++info;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800148 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700149
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700150 // Parse /data/system/packages.list
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700151 uid_t userId = uid % AID_USER;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700152 const char *name = android::uidToName(userId);
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700153 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
154 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
155 }
Mark Salyzyn08739ba2015-03-16 08:26:05 -0700156 if (name) {
157 return name;
158 }
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700159
160 // report uid -> pid(s) -> pidToName if unique
Mark Salyzyn758058f2015-08-21 16:44:30 -0700161 for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700162 const PidEntry &entry = it->second;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700163
164 if (entry.getUid() == uid) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700165 const char *nameTmp = entry.getName();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700166
Mark Salyzyn758058f2015-08-21 16:44:30 -0700167 if (nameTmp) {
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700168 if (!name) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700169 name = strdup(nameTmp);
170 } else if (fast<strcmp>(name, nameTmp)) {
171 free(const_cast<char *>(name));
Mark Salyzyn023f51f2015-04-29 12:48:45 -0700172 name = NULL;
173 break;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700174 }
175 }
176 }
177 }
178
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700179 // No one
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700180 return name;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800181}
182
Mark Salyzyn758058f2015-08-21 16:44:30 -0700183std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
184 bool isprune = worstUidEnabledForLogid(id);
185 return formatLine(android::base::StringPrintf(
186 name.c_str(), android_log_id_to_name(id)),
187 std::string("Size"),
188 std::string(isprune ? "Pruned" : ""))
189 + formatLine(std::string("UID PACKAGE"),
190 std::string("BYTES"),
191 std::string(isprune ? "NUM" : ""));
Mark Salyzyn34facab2014-02-06 14:48:50 -0800192}
193
Mark Salyzyn758058f2015-08-21 16:44:30 -0700194std::string UidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
195 uid_t uid = getKey();
196 std::string name = android::base::StringPrintf("%u", uid);
197 const char *nameTmp = stat.uidToName(uid);
198 if (nameTmp) {
199 name += android::base::StringPrintf(
200 "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
201 "", nameTmp);
202 free(const_cast<char *>(nameTmp));
203 }
204
205 std::string size = android::base::StringPrintf("%zu", getSizes());
206
207 std::string pruned = "";
208 size_t dropped = getDropped();
209 if (dropped) {
210 pruned = android::base::StringPrintf("%zu", dropped);
211 }
212
213 return formatLine(name, size, pruned);
214}
215
216std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
217 return formatLine(name,
218 std::string("Size"),
219 std::string("Pruned"))
220 + formatLine(std::string(" PID/UID COMMAND LINE"),
221 std::string("BYTES"),
222 std::string("NUM"));
223}
224
225std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
226 uid_t uid = getUid();
227 std::string name = android::base::StringPrintf("%5u/%u",
228 getKey(), uid);
229 const char *nameTmp = getName();
230 if (nameTmp) {
231 name += android::base::StringPrintf(
232 "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
233 "", nameTmp);
234 } else if ((nameTmp = stat.uidToName(uid))) {
235 name += android::base::StringPrintf(
236 "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
237 "", nameTmp);
238 free(const_cast<char *>(nameTmp));
239 }
240
241 std::string size = android::base::StringPrintf("%zu",
242 getSizes());
243
244 std::string pruned = "";
245 size_t dropped = getDropped();
246 if (dropped) {
247 pruned = android::base::StringPrintf("%zu", dropped);
248 }
249
250 return formatLine(name, size, pruned);
251}
252
253std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
254 return formatLine(name,
255 std::string("Size"),
256 std::string("Pruned"))
257 + formatLine(std::string(" TID/UID COMM"),
258 std::string("BYTES"),
259 std::string("NUM"));
260}
261
262std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
263 uid_t uid = getUid();
264 std::string name = android::base::StringPrintf("%5u/%u",
265 getKey(), uid);
266 const char *nameTmp = getName();
267 if (nameTmp) {
268 name += android::base::StringPrintf(
269 "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
270 "", nameTmp);
271 } else if ((nameTmp = stat.uidToName(uid))) {
272 // if we do not have a PID name, lets punt to try UID name?
273 name += android::base::StringPrintf(
274 "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
275 "", nameTmp);
276 free(const_cast<char *>(nameTmp));
277 // We tried, better to not have a name at all, we still
278 // have TID/UID by number to report in any case.
279 }
280
281 std::string size = android::base::StringPrintf("%zu",
282 getSizes());
283
284 std::string pruned = "";
285 size_t dropped = getDropped();
286 if (dropped) {
287 pruned = android::base::StringPrintf("%zu", dropped);
288 }
289
290 return formatLine(name, size, pruned);
291}
292
293std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
294 bool isprune = worstUidEnabledForLogid(id);
295 return formatLine(name,
296 std::string("Size"),
297 std::string(isprune ? "Prune" : ""))
298 + formatLine(std::string(" TAG/UID TAGNAME"),
299 std::string("BYTES"),
300 std::string(isprune ? "NUM" : ""));
301}
302
303std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
304 std::string name;
305 uid_t uid = getUid();
306 if (uid == (uid_t)-1) {
307 name = android::base::StringPrintf("%7u",
308 getKey());
309 } else {
310 name = android::base::StringPrintf("%7u/%u",
311 getKey(), uid);
312 }
313 const char *nameTmp = getName();
314 if (nameTmp) {
315 name += android::base::StringPrintf(
316 "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
317 "", nameTmp);
318 }
319
320 std::string size = android::base::StringPrintf("%zu",
321 getSizes());
322
323 std::string pruned = "";
324
325 return formatLine(name, size, pruned);
326}
327
328std::string LogStatistics::format(uid_t uid, unsigned int logMask) const {
Mark Salyzyn9a038632014-04-07 07:05:40 -0700329 static const unsigned short spaces_total = 19;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800330
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700331 // Report on total logging, current and for all time
Mark Salyzyn34facab2014-02-06 14:48:50 -0800332
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700333 std::string output = "size/num";
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700334 size_t oldLength;
335 short spaces = 1;
336
337 log_id_for_each(id) {
338 if (!(logMask & (1 << id))) {
Mark Salyzync8a576c2014-04-04 16:35:59 -0700339 continue;
340 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700341 oldLength = output.length();
Mark Salyzync8a576c2014-04-04 16:35:59 -0700342 if (spaces < 0) {
343 spaces = 0;
344 }
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700345 output += android::base::StringPrintf("%*s%s", spaces, "",
346 android_log_id_to_name(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700347 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800348 }
349
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700350 spaces = 4;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700351 output += "\nTotal";
Mark Salyzyn34facab2014-02-06 14:48:50 -0800352
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700353 log_id_for_each(id) {
354 if (!(logMask & (1 << id))) {
355 continue;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800356 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700357 oldLength = output.length();
358 if (spaces < 0) {
359 spaces = 0;
360 }
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700361 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
362 sizesTotal(id),
363 elementsTotal(id));
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700364 spaces += spaces_total + oldLength - output.length();
Mark Salyzyn34facab2014-02-06 14:48:50 -0800365 }
366
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700367 spaces = 6;
Mark Salyzyn758058f2015-08-21 16:44:30 -0700368 output += "\nNow";
Mark Salyzyn34facab2014-02-06 14:48:50 -0800369
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700370 log_id_for_each(id) {
371 if (!(logMask & (1 << id))) {
Mark Salyzyn34facab2014-02-06 14:48:50 -0800372 continue;
373 }
374
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700375 size_t els = elements(id);
Mark Salyzyn34facab2014-02-06 14:48:50 -0800376 if (els) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700377 oldLength = output.length();
Mark Salyzyne457b742014-02-19 17:18:31 -0800378 if (spaces < 0) {
379 spaces = 0;
380 }
Mark Salyzyndecbcd92015-08-19 15:33:01 -0700381 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
382 sizes(id), els);
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700383 spaces -= output.length() - oldLength;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800384 }
385 spaces += spaces_total;
386 }
387
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700388 // Report on Chattiest
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700389
Mark Salyzyn758058f2015-08-21 16:44:30 -0700390 std::string name;
391
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700392 // Chattiest by application (UID)
393 log_id_for_each(id) {
394 if (!(logMask & (1 << id))) {
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700395 continue;
396 }
397
Mark Salyzyn758058f2015-08-21 16:44:30 -0700398 name = (uid == AID_ROOT)
399 ? "Chattiest UIDs in %s log buffer:"
400 : "Logging for your UID in %s log buffer:";
401 output += uidTable[id].format(*this, uid, name, id);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700402 }
Mark Salyzyn8e72c532014-03-26 10:46:39 -0700403
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700404 if (enable) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700405 name = (uid == AID_ROOT) ? "Chattiest PIDs:" : "Logging for this PID:";
406 output += pidTable.format(*this, uid, name);
407 name = "Chattiest TIDs:";
408 output += tidTable.format(*this, uid, name);
Mark Salyzyn17ed6792015-04-20 13:35:15 -0700409 }
410
Mark Salyzyn344bff42015-04-13 14:24:45 -0700411 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
Mark Salyzyn758058f2015-08-21 16:44:30 -0700412 name = "Chattiest events log buffer TAGs:";
413 output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
Mark Salyzyn344bff42015-04-13 14:24:45 -0700414 }
415
Mark Salyzyn73160ac2015-08-20 10:01:44 -0700416 return output;
Mark Salyzyn34facab2014-02-06 14:48:50 -0800417}
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700418
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700419namespace android {
420
421uid_t pidToUid(pid_t pid) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700422 char buffer[512];
423 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
424 FILE *fp = fopen(buffer, "r");
425 if (fp) {
426 while (fgets(buffer, sizeof(buffer), fp)) {
427 int uid;
Mark Salyzync32afdf2015-04-14 13:07:29 -0700428 if (sscanf(buffer, "Uid: %d", &uid) == 1) {
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700429 fclose(fp);
430 return uid;
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700431 }
432 }
Mark Salyzyn97c1c2b2015-03-10 13:51:35 -0700433 fclose(fp);
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700434 }
Mark Salyzyne3aeeee2015-03-17 07:56:32 -0700435 return AID_LOGD; // associate this with the logger
Mark Salyzyn4ba03872014-04-07 07:15:33 -0700436}
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700437
438}
439
440uid_t LogStatistics::pidToUid(pid_t pid) {
Mark Salyzyn511338d2015-05-19 09:12:30 -0700441 return pidTable.add(pid)->second.getUid();
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700442}
443
444// caller must free character string
Mark Salyzyn758058f2015-08-21 16:44:30 -0700445const char *LogStatistics::pidToName(pid_t pid) const {
446 // An inconvenient truth ... getName() can alter the object
447 pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
448 const char *name = writablePidTable.add(pid)->second.getName();
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700449 if (!name) {
450 return NULL;
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700451 }
Mark Salyzyn81b3eab2015-04-13 14:24:45 -0700452 return strdup(name);
Mark Salyzyn720f6d12015-03-16 08:26:05 -0700453}