1 /*
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
17 #include <ctype.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <pwd.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <list>
27
28 #include <private/android_logger.h>
29
30 #include "LogStatistics.h"
31
32 static const uint64_t hourSec = 60 * 60;
33 static const uint64_t monthSec = 31 * 24 * hourSec;
34
35 size_t LogStatistics::SizesTotal;
36
LogStatistics()37 LogStatistics::LogStatistics() : enable(false) {
38 log_time now(CLOCK_REALTIME);
39 log_id_for_each(id) {
40 mSizes[id] = 0;
41 mElements[id] = 0;
42 mDroppedElements[id] = 0;
43 mSizesTotal[id] = 0;
44 mElementsTotal[id] = 0;
45 mOldest[id] = now;
46 mNewest[id] = now;
47 mNewestDropped[id] = now;
48 }
49 }
50
51 namespace android {
52
sizesTotal()53 size_t sizesTotal() {
54 return LogStatistics::sizesTotal();
55 }
56
57 // caller must own and free character string
pidToName(pid_t pid)58 char* pidToName(pid_t pid) {
59 char* retval = NULL;
60 if (pid == 0) { // special case from auditd/klogd for kernel
61 retval = strdup("logd");
62 } else {
63 char buffer[512];
64 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
65 int fd = open(buffer, O_RDONLY);
66 if (fd >= 0) {
67 ssize_t ret = read(fd, buffer, sizeof(buffer));
68 if (ret > 0) {
69 buffer[sizeof(buffer) - 1] = '\0';
70 // frameworks intermediate state
71 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
72 retval = strdup(buffer);
73 }
74 }
75 close(fd);
76 }
77 }
78 return retval;
79 }
80 }
81
addTotal(LogBufferElement * element)82 void LogStatistics::addTotal(LogBufferElement* element) {
83 if (element->getDropped()) return;
84
85 log_id_t log_id = element->getLogId();
86 unsigned short size = element->getMsgLen();
87 mSizesTotal[log_id] += size;
88 SizesTotal += size;
89 ++mElementsTotal[log_id];
90 }
91
add(LogBufferElement * element)92 void LogStatistics::add(LogBufferElement* element) {
93 log_id_t log_id = element->getLogId();
94 unsigned short size = element->getMsgLen();
95 mSizes[log_id] += size;
96 ++mElements[log_id];
97
98 // When caller adding a chatty entry, they will have already
99 // called add() and subtract() for each entry as they are
100 // evaluated and trimmed, thus recording size and number of
101 // elements, but we must recognize the manufactured dropped
102 // entry as not contributing to the lifetime totals.
103 if (element->getDropped()) {
104 ++mDroppedElements[log_id];
105 } else {
106 mSizesTotal[log_id] += size;
107 SizesTotal += size;
108 ++mElementsTotal[log_id];
109 }
110
111 log_time stamp(element->getRealTime());
112 if (mNewest[log_id] < stamp) {
113 // A major time update invalidates the statistics :-(
114 log_time diff = stamp - mNewest[log_id];
115 mNewest[log_id] = stamp;
116
117 if (diff.tv_sec > hourSec) {
118 // approximate Do-Your-Best fixup
119 diff += mOldest[log_id];
120 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
121 diff = stamp;
122 }
123 if (diff <= stamp) {
124 mOldest[log_id] = diff;
125 if (mNewestDropped[log_id] < diff) {
126 mNewestDropped[log_id] = diff;
127 }
128 }
129 }
130 }
131
132 if (log_id == LOG_ID_KERNEL) {
133 return;
134 }
135
136 uidTable[log_id].add(element->getUid(), element);
137 if (element->getUid() == AID_SYSTEM) {
138 pidSystemTable[log_id].add(element->getPid(), element);
139 }
140
141 if (!enable) {
142 return;
143 }
144
145 pidTable.add(element->getPid(), element);
146 tidTable.add(element->getTid(), element);
147
148 uint32_t tag = element->getTag();
149 if (tag) {
150 if (log_id == LOG_ID_SECURITY) {
151 securityTagTable.add(tag, element);
152 } else {
153 tagTable.add(tag, element);
154 }
155 }
156
157 if (!element->getDropped()) {
158 tagNameTable.add(TagNameKey(element), element);
159 }
160 }
161
subtract(LogBufferElement * element)162 void LogStatistics::subtract(LogBufferElement* element) {
163 log_id_t log_id = element->getLogId();
164 unsigned short size = element->getMsgLen();
165 mSizes[log_id] -= size;
166 --mElements[log_id];
167 if (element->getDropped()) {
168 --mDroppedElements[log_id];
169 }
170
171 if (mOldest[log_id] < element->getRealTime()) {
172 mOldest[log_id] = element->getRealTime();
173 }
174
175 if (log_id == LOG_ID_KERNEL) {
176 return;
177 }
178
179 uidTable[log_id].subtract(element->getUid(), element);
180 if (element->getUid() == AID_SYSTEM) {
181 pidSystemTable[log_id].subtract(element->getPid(), element);
182 }
183
184 if (!enable) {
185 return;
186 }
187
188 pidTable.subtract(element->getPid(), element);
189 tidTable.subtract(element->getTid(), element);
190
191 uint32_t tag = element->getTag();
192 if (tag) {
193 if (log_id == LOG_ID_SECURITY) {
194 securityTagTable.subtract(tag, element);
195 } else {
196 tagTable.subtract(tag, element);
197 }
198 }
199
200 if (!element->getDropped()) {
201 tagNameTable.subtract(TagNameKey(element), element);
202 }
203 }
204
205 // Atomically set an entry to drop
206 // entry->setDropped(1) must follow this call, caller should do this explicitly.
drop(LogBufferElement * element)207 void LogStatistics::drop(LogBufferElement* element) {
208 log_id_t log_id = element->getLogId();
209 unsigned short size = element->getMsgLen();
210 mSizes[log_id] -= size;
211 ++mDroppedElements[log_id];
212
213 if (mNewestDropped[log_id] < element->getRealTime()) {
214 mNewestDropped[log_id] = element->getRealTime();
215 }
216
217 uidTable[log_id].drop(element->getUid(), element);
218 if (element->getUid() == AID_SYSTEM) {
219 pidSystemTable[log_id].drop(element->getPid(), element);
220 }
221
222 if (!enable) {
223 return;
224 }
225
226 pidTable.drop(element->getPid(), element);
227 tidTable.drop(element->getTid(), element);
228
229 uint32_t tag = element->getTag();
230 if (tag) {
231 if (log_id == LOG_ID_SECURITY) {
232 securityTagTable.drop(tag, element);
233 } else {
234 tagTable.drop(tag, element);
235 }
236 }
237
238 tagNameTable.subtract(TagNameKey(element), element);
239 }
240
241 // caller must own and free character string
242 // Requires parent LogBuffer::wrlock() to be held
uidToName(uid_t uid) const243 const char* LogStatistics::uidToName(uid_t uid) const {
244 // Local hard coded favourites
245 if (uid == AID_LOGD) {
246 return strdup("auditd");
247 }
248
249 // Android system
250 if (uid < AID_APP) {
251 // in bionic, thread safe as long as we copy the results
252 struct passwd* pwd = getpwuid(uid);
253 if (pwd) {
254 return strdup(pwd->pw_name);
255 }
256 }
257
258 // Parse /data/system/packages.list
259 uid_t userId = uid % AID_USER_OFFSET;
260 const char* name = android::uidToName(userId);
261 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
262 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
263 }
264 if (name) {
265 return name;
266 }
267
268 // Android application
269 if (uid >= AID_APP) {
270 struct passwd* pwd = getpwuid(uid);
271 if (pwd) {
272 return strdup(pwd->pw_name);
273 }
274 }
275
276 // report uid -> pid(s) -> pidToName if unique
277 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
278 ++it) {
279 const PidEntry& entry = it->second;
280
281 if (entry.getUid() == uid) {
282 const char* nameTmp = entry.getName();
283
284 if (nameTmp) {
285 if (!name) {
286 name = strdup(nameTmp);
287 } else if (fastcmp<strcmp>(name, nameTmp)) {
288 free(const_cast<char*>(name));
289 name = NULL;
290 break;
291 }
292 }
293 }
294 }
295
296 // No one
297 return name;
298 }
299
formatHeader(const std::string & name,log_id_t id) const300 std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
301 bool isprune = worstUidEnabledForLogid(id);
302 return formatLine(android::base::StringPrintf(name.c_str(),
303 android_log_id_to_name(id)),
304 std::string("Size"),
305 std::string(isprune ? "+/- Pruned" : "")) +
306 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
307 std::string(isprune ? "NUM" : ""));
308 }
309
310 // Helper to truncate name, if too long, and add name dressings
formatTmp(const LogStatistics & stat,const char * nameTmp,uid_t uid,std::string & name,std::string & size,size_t nameLen)311 static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
312 std::string& name, std::string& size, size_t nameLen) {
313 const char* allocNameTmp = nullptr;
314 if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
315 if (nameTmp) {
316 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
317 size_t len = EntryBaseConstants::total_len -
318 EntryBaseConstants::pruned_len - size.length() -
319 name.length() - lenSpace - 2;
320 size_t lenNameTmp = strlen(nameTmp);
321 while ((len < lenNameTmp) && (lenSpace > 1)) {
322 ++len;
323 --lenSpace;
324 }
325 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
326 if (len < lenNameTmp) {
327 name += "...";
328 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
329 }
330 name += nameTmp;
331 free(const_cast<char*>(allocNameTmp));
332 }
333 }
334
format(const LogStatistics & stat,log_id_t id) const335 std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
336 uid_t uid = getUid();
337 std::string name = android::base::StringPrintf("%u", uid);
338 std::string size = android::base::StringPrintf("%zu", getSizes());
339
340 formatTmp(stat, nullptr, uid, name, size, 6);
341
342 std::string pruned = "";
343 if (worstUidEnabledForLogid(id)) {
344 size_t totalDropped = 0;
345 for (LogStatistics::uidTable_t::const_iterator it =
346 stat.uidTable[id].begin();
347 it != stat.uidTable[id].end(); ++it) {
348 totalDropped += it->second.getDropped();
349 }
350 size_t sizes = stat.sizes(id);
351 size_t totalSize = stat.sizesTotal(id);
352 size_t totalElements = stat.elementsTotal(id);
353 float totalVirtualSize =
354 (float)sizes + (float)totalDropped * totalSize / totalElements;
355 size_t entrySize = getSizes();
356 float virtualEntrySize = entrySize;
357 int realPermille = virtualEntrySize * 1000.0 / sizes;
358 size_t dropped = getDropped();
359 if (dropped) {
360 pruned = android::base::StringPrintf("%zu", dropped);
361 virtualEntrySize += (float)dropped * totalSize / totalElements;
362 }
363 int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
364 int permille =
365 (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
366 if ((permille < -1) || (1 < permille)) {
367 std::string change;
368 const char* units = "%";
369 const char* prefix = (permille > 0) ? "+" : "";
370
371 if (permille > 999) {
372 permille = (permille + 1000) / 100; // Now tenths fold
373 units = "X";
374 prefix = "";
375 }
376 if ((-99 < permille) && (permille < 99)) {
377 change = android::base::StringPrintf(
378 "%s%d.%u%s", prefix, permille / 10,
379 ((permille < 0) ? (-permille % 10) : (permille % 10)),
380 units);
381 } else {
382 change = android::base::StringPrintf(
383 "%s%d%s", prefix, (permille + 5) / 10, units);
384 }
385 ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
386 pruned.length() - change.length();
387 if ((spaces <= 0) && pruned.length()) {
388 spaces = 1;
389 }
390 if (spaces > 0) {
391 change += android::base::StringPrintf("%*s", (int)spaces, "");
392 }
393 pruned = change + pruned;
394 }
395 }
396
397 std::string output = formatLine(name, size, pruned);
398
399 if (uid != AID_SYSTEM) {
400 return output;
401 }
402
403 static const size_t maximum_sorted_entries = 32;
404 std::unique_ptr<const PidEntry* []> sorted =
405 stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
406
407 if (!sorted.get()) {
408 return output;
409 }
410 std::string byPid;
411 size_t index;
412 bool hasDropped = false;
413 for (index = 0; index < maximum_sorted_entries; ++index) {
414 const PidEntry* entry = sorted[index];
415 if (!entry) {
416 break;
417 }
418 if (entry->getSizes() <= (getSizes() / 100)) {
419 break;
420 }
421 if (entry->getDropped()) {
422 hasDropped = true;
423 }
424 byPid += entry->format(stat, id);
425 }
426 if (index > 1) { // print this only if interesting
427 std::string ditto("\" ");
428 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
429 hasDropped ? ditto : std::string(""));
430 output += byPid;
431 }
432
433 return output;
434 }
435
formatHeader(const std::string & name,log_id_t) const436 std::string PidEntry::formatHeader(const std::string& name,
437 log_id_t /* id */) const {
438 return formatLine(name, std::string("Size"), std::string("Pruned")) +
439 formatLine(std::string(" PID/UID COMMAND LINE"),
440 std::string("BYTES"), std::string("NUM"));
441 }
442
format(const LogStatistics & stat,log_id_t) const443 std::string PidEntry::format(const LogStatistics& stat,
444 log_id_t /* id */) const {
445 uid_t uid = getUid();
446 pid_t pid = getPid();
447 std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
448 std::string size = android::base::StringPrintf("%zu", getSizes());
449
450 formatTmp(stat, getName(), uid, name, size, 12);
451
452 std::string pruned = "";
453 size_t dropped = getDropped();
454 if (dropped) {
455 pruned = android::base::StringPrintf("%zu", dropped);
456 }
457
458 return formatLine(name, size, pruned);
459 }
460
formatHeader(const std::string & name,log_id_t) const461 std::string TidEntry::formatHeader(const std::string& name,
462 log_id_t /* id */) const {
463 return formatLine(name, std::string("Size"), std::string("Pruned")) +
464 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
465 std::string("NUM"));
466 }
467
format(const LogStatistics & stat,log_id_t) const468 std::string TidEntry::format(const LogStatistics& stat,
469 log_id_t /* id */) const {
470 uid_t uid = getUid();
471 std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
472 std::string size = android::base::StringPrintf("%zu", getSizes());
473
474 formatTmp(stat, getName(), uid, name, size, 12);
475
476 std::string pruned = "";
477 size_t dropped = getDropped();
478 if (dropped) {
479 pruned = android::base::StringPrintf("%zu", dropped);
480 }
481
482 return formatLine(name, size, pruned);
483 }
484
formatHeader(const std::string & name,log_id_t id) const485 std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
486 bool isprune = worstUidEnabledForLogid(id);
487 return formatLine(name, std::string("Size"),
488 std::string(isprune ? "Prune" : "")) +
489 formatLine(std::string(" TAG/UID TAGNAME"),
490 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
491 }
492
format(const LogStatistics &,log_id_t) const493 std::string TagEntry::format(const LogStatistics& /* stat */,
494 log_id_t /* id */) const {
495 std::string name;
496 uid_t uid = getUid();
497 if (uid == (uid_t)-1) {
498 name = android::base::StringPrintf("%7u", getKey());
499 } else {
500 name = android::base::StringPrintf("%7u/%u", getKey(), uid);
501 }
502 const char* nameTmp = getName();
503 if (nameTmp) {
504 name += android::base::StringPrintf(
505 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
506 }
507
508 std::string size = android::base::StringPrintf("%zu", getSizes());
509
510 std::string pruned = "";
511 size_t dropped = getDropped();
512 if (dropped) {
513 pruned = android::base::StringPrintf("%zu", dropped);
514 }
515
516 return formatLine(name, size, pruned);
517 }
518
formatHeader(const std::string & name,log_id_t) const519 std::string TagNameEntry::formatHeader(const std::string& name,
520 log_id_t /* id */) const {
521 return formatLine(name, std::string("Size"), std::string("")) +
522 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
523 std::string("BYTES"), std::string(""));
524 }
525
format(const LogStatistics &,log_id_t) const526 std::string TagNameEntry::format(const LogStatistics& /* stat */,
527 log_id_t /* id */) const {
528 std::string name;
529 pid_t tid = getTid();
530 pid_t pid = getPid();
531 std::string pidstr;
532 if (pid != (pid_t)-1) {
533 pidstr = android::base::StringPrintf("%u", pid);
534 if ((tid != (pid_t)-1) && (tid != pid)) pidstr = "/" + pidstr;
535 }
536 int len = 9 - pidstr.length();
537 if (len < 0) len = 0;
538 if ((tid == (pid_t)-1) || (tid == pid)) {
539 name = android::base::StringPrintf("%*s", len, "");
540 } else {
541 name = android::base::StringPrintf("%*u", len, tid);
542 }
543 name += pidstr;
544 uid_t uid = getUid();
545 if (uid != (uid_t)-1) {
546 name += android::base::StringPrintf("/%u", uid);
547 }
548
549 std::string size = android::base::StringPrintf("%zu", getSizes());
550
551 const char* nameTmp = getName();
552 if (nameTmp) {
553 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
554 size_t len = EntryBaseConstants::total_len -
555 EntryBaseConstants::pruned_len - size.length() -
556 name.length() - lenSpace - 2;
557 size_t lenNameTmp = strlen(nameTmp);
558 while ((len < lenNameTmp) && (lenSpace > 1)) {
559 ++len;
560 --lenSpace;
561 }
562 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
563 if (len < lenNameTmp) {
564 name += "...";
565 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
566 }
567 name += nameTmp;
568 }
569
570 std::string pruned = "";
571
572 return formatLine(name, size, pruned);
573 }
574
formatMsec(uint64_t val)575 static std::string formatMsec(uint64_t val) {
576 static const unsigned subsecDigits = 3;
577 static const uint64_t sec = MS_PER_SEC;
578
579 static const uint64_t minute = 60 * sec;
580 static const uint64_t hour = 60 * minute;
581 static const uint64_t day = 24 * hour;
582
583 std::string output;
584 if (val < sec) return output;
585
586 if (val >= day) {
587 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
588 val = (val % day) + day;
589 }
590 if (val >= minute) {
591 if (val >= hour) {
592 output += android::base::StringPrintf("%" PRIu64 ":",
593 (val / hour) % (day / hour));
594 }
595 output += android::base::StringPrintf(
596 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
597 (val / minute) % (hour / minute));
598 }
599 output +=
600 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
601 (val / sec) % (minute / sec));
602 val %= sec;
603 unsigned digits = subsecDigits;
604 while (digits && ((val % 10) == 0)) {
605 val /= 10;
606 --digits;
607 }
608 if (digits) {
609 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
610 }
611 return output;
612 }
613
format(uid_t uid,pid_t pid,unsigned int logMask) const614 std::string LogStatistics::format(uid_t uid, pid_t pid,
615 unsigned int logMask) const {
616 static const unsigned short spaces_total = 19;
617
618 // Report on total logging, current and for all time
619
620 std::string output = "size/num";
621 size_t oldLength;
622 short spaces = 1;
623
624 log_id_for_each(id) {
625 if (!(logMask & (1 << id))) continue;
626 oldLength = output.length();
627 if (spaces < 0) spaces = 0;
628 output += android::base::StringPrintf("%*s%s", spaces, "",
629 android_log_id_to_name(id));
630 spaces += spaces_total + oldLength - output.length();
631 }
632 if (spaces < 0) spaces = 0;
633 output += android::base::StringPrintf("%*sTotal", spaces, "");
634
635 static const char TotalStr[] = "\nTotal";
636 spaces = 10 - strlen(TotalStr);
637 output += TotalStr;
638
639 size_t totalSize = 0;
640 size_t totalEls = 0;
641 log_id_for_each(id) {
642 if (!(logMask & (1 << id))) continue;
643 oldLength = output.length();
644 if (spaces < 0) spaces = 0;
645 size_t szs = sizesTotal(id);
646 totalSize += szs;
647 size_t els = elementsTotal(id);
648 totalEls += els;
649 output +=
650 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
651 spaces += spaces_total + oldLength - output.length();
652 }
653 if (spaces < 0) spaces = 0;
654 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
655 totalEls);
656
657 static const char NowStr[] = "\nNow";
658 spaces = 10 - strlen(NowStr);
659 output += NowStr;
660
661 totalSize = 0;
662 totalEls = 0;
663 log_id_for_each(id) {
664 if (!(logMask & (1 << id))) continue;
665
666 size_t els = elements(id);
667 if (els) {
668 oldLength = output.length();
669 if (spaces < 0) spaces = 0;
670 size_t szs = sizes(id);
671 totalSize += szs;
672 totalEls += els;
673 output +=
674 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
675 spaces -= output.length() - oldLength;
676 }
677 spaces += spaces_total;
678 }
679 if (spaces < 0) spaces = 0;
680 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
681 totalEls);
682
683 static const char SpanStr[] = "\nLogspan";
684 spaces = 10 - strlen(SpanStr);
685 output += SpanStr;
686
687 // Total reports the greater of the individual maximum time span, or the
688 // validated minimum start and maximum end time span if it makes sense.
689 uint64_t minTime = UINT64_MAX;
690 uint64_t maxTime = 0;
691 uint64_t maxSpan = 0;
692 totalSize = 0;
693
694 log_id_for_each(id) {
695 if (!(logMask & (1 << id))) continue;
696
697 // validity checking
698 uint64_t oldest = mOldest[id].msec();
699 uint64_t newest = mNewest[id].msec();
700 if (newest <= oldest) {
701 spaces += spaces_total;
702 continue;
703 }
704
705 uint64_t span = newest - oldest;
706 if (span > (monthSec * MS_PER_SEC)) {
707 spaces += spaces_total;
708 continue;
709 }
710
711 // total span
712 if (minTime > oldest) minTime = oldest;
713 if (maxTime < newest) maxTime = newest;
714 if (span > maxSpan) maxSpan = span;
715 totalSize += span;
716
717 uint64_t dropped = mNewestDropped[id].msec();
718 if (dropped < oldest) dropped = oldest;
719 if (dropped > newest) dropped = newest;
720
721 oldLength = output.length();
722 output += android::base::StringPrintf("%*s%s", spaces, "",
723 formatMsec(span).c_str());
724 unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
725 if ((permille > 1) && (permille < 999)) {
726 output += android::base::StringPrintf("(%u", permille / 10);
727 permille %= 10;
728 if (permille) {
729 output += android::base::StringPrintf(".%u", permille);
730 }
731 output += android::base::StringPrintf("%%)");
732 }
733 spaces -= output.length() - oldLength;
734 spaces += spaces_total;
735 }
736 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
737 (maxTime > maxSpan)) {
738 maxSpan = maxTime;
739 }
740 if (spaces < 0) spaces = 0;
741 output += android::base::StringPrintf("%*s%s", spaces, "",
742 formatMsec(maxSpan).c_str());
743
744 static const char OverheadStr[] = "\nOverhead";
745 spaces = 10 - strlen(OverheadStr);
746 output += OverheadStr;
747
748 totalSize = 0;
749 log_id_for_each(id) {
750 if (!(logMask & (1 << id))) continue;
751
752 size_t els = elements(id);
753 if (els) {
754 oldLength = output.length();
755 if (spaces < 0) spaces = 0;
756 // estimate the std::list overhead.
757 static const size_t overhead =
758 ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
759 -sizeof(uint64_t)) +
760 sizeof(std::list<LogBufferElement*>);
761 size_t szs = sizes(id) + els * overhead;
762 totalSize += szs;
763 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
764 spaces -= output.length() - oldLength;
765 }
766 spaces += spaces_total;
767 }
768 totalSize += sizeOf();
769 if (spaces < 0) spaces = 0;
770 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
771
772 // Report on Chattiest
773
774 std::string name;
775
776 // Chattiest by application (UID)
777 log_id_for_each(id) {
778 if (!(logMask & (1 << id))) continue;
779
780 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
781 : "Logging for your UID in %s log buffer:";
782 output += uidTable[id].format(*this, uid, pid, name, id);
783 }
784
785 if (enable) {
786 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
787 : "Logging for this PID:";
788 output += pidTable.format(*this, uid, pid, name);
789 name = "Chattiest TIDs";
790 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
791 name += ":";
792 output += tidTable.format(*this, uid, pid, name);
793 }
794
795 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
796 name = "Chattiest events log buffer TAGs";
797 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
798 name += ":";
799 output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
800 }
801
802 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
803 name = "Chattiest security log buffer TAGs";
804 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
805 name += ":";
806 output +=
807 securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
808 }
809
810 if (enable) {
811 name = "Chattiest TAGs";
812 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
813 name += ":";
814 output += tagNameTable.format(*this, uid, pid, name);
815 }
816
817 return output;
818 }
819
820 namespace android {
821
pidToUid(pid_t pid)822 uid_t pidToUid(pid_t pid) {
823 char buffer[512];
824 snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
825 FILE* fp = fopen(buffer, "r");
826 if (fp) {
827 while (fgets(buffer, sizeof(buffer), fp)) {
828 int uid = AID_LOGD;
829 char space = 0;
830 if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
831 isspace(space)) {
832 fclose(fp);
833 return uid;
834 }
835 }
836 fclose(fp);
837 }
838 return AID_LOGD; // associate this with the logger
839 }
840
tidToPid(pid_t tid)841 pid_t tidToPid(pid_t tid) {
842 char buffer[512];
843 snprintf(buffer, sizeof(buffer), "/proc/%u/status", tid);
844 FILE* fp = fopen(buffer, "r");
845 if (fp) {
846 while (fgets(buffer, sizeof(buffer), fp)) {
847 int pid = tid;
848 char space = 0;
849 if ((sscanf(buffer, "Tgid: %d%c", &pid, &space) == 2) &&
850 isspace(space)) {
851 fclose(fp);
852 return pid;
853 }
854 }
855 fclose(fp);
856 }
857 return tid;
858 }
859 }
860
pidToUid(pid_t pid)861 uid_t LogStatistics::pidToUid(pid_t pid) {
862 return pidTable.add(pid)->second.getUid();
863 }
864
tidToPid(pid_t tid)865 pid_t LogStatistics::tidToPid(pid_t tid) {
866 return tidTable.add(tid)->second.getPid();
867 }
868
869 // caller must free character string
pidToName(pid_t pid) const870 const char* LogStatistics::pidToName(pid_t pid) const {
871 // An inconvenient truth ... getName() can alter the object
872 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
873 const char* name = writablePidTable.add(pid)->second.getName();
874 if (!name) {
875 return NULL;
876 }
877 return strdup(name);
878 }
879