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 "LogStatistics.h"
18
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <inttypes.h>
22 #include <pwd.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include <list>
30 #include <vector>
31
32 #include <android-base/logging.h>
33 #include <android-base/strings.h>
34 #include <private/android_logger.h>
35
36 #include "LogBufferElement.h"
37
38 static const uint64_t hourSec = 60 * 60;
39 static const uint64_t monthSec = 31 * 24 * hourSec;
40
41 std::atomic<size_t> LogStatistics::SizesTotal;
42
TagNameKey(const LogStatisticsElement & element)43 static std::string TagNameKey(const LogStatisticsElement& element) {
44 if (IsBinary(element.log_id)) {
45 uint32_t tag = element.tag;
46 if (tag) {
47 const char* cp = android::tagToName(tag);
48 if (cp) {
49 return std::string(cp);
50 }
51 }
52 return android::base::StringPrintf("[%" PRIu32 "]", tag);
53 }
54 const char* msg = element.msg;
55 ++msg;
56 uint16_t len = element.msg_len;
57 len = (len <= 1) ? 0 : strnlen(msg, len - 1);
58 if (!len) {
59 return "<NULL>";
60 }
61 return std::string(msg, len);
62 }
63
LogStatistics(bool enable_statistics,bool track_total_size,std::optional<log_time> start_time)64 LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
65 std::optional<log_time> start_time)
66 : enable(enable_statistics), track_total_size_(track_total_size) {
67 log_time now(CLOCK_REALTIME);
68 log_id_for_each(id) {
69 mSizes[id] = 0;
70 mElements[id] = 0;
71 mSizesTotal[id] = 0;
72 mElementsTotal[id] = 0;
73 if (start_time) {
74 mOldest[id] = *start_time;
75 mNewest[id] = *start_time;
76 } else {
77 mOldest[id] = now;
78 mNewest[id] = now;
79 }
80 }
81 }
82
83 namespace android {
84
sizesTotal()85 size_t sizesTotal() {
86 return LogStatistics::sizesTotal();
87 }
88
89 // caller must own and free character string
pidToName(pid_t pid)90 char* pidToName(pid_t pid) {
91 char* retval = nullptr;
92 if (pid == 0) { // special case from auditd/klogd for kernel
93 retval = strdup("logd");
94 } else {
95 char buffer[512];
96 snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
97 int fd = open(buffer, O_RDONLY | O_CLOEXEC);
98 if (fd >= 0) {
99 ssize_t ret = read(fd, buffer, sizeof(buffer));
100 if (ret > 0) {
101 buffer[sizeof(buffer) - 1] = '\0';
102 // frameworks intermediate state
103 if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
104 retval = strdup(buffer);
105 }
106 }
107 close(fd);
108 }
109 }
110 return retval;
111 }
112 }
113
AddTotal(log_id_t log_id,uint16_t size)114 void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
115 auto lock = std::lock_guard{lock_};
116
117 mSizesTotal[log_id] += size;
118 SizesTotal += size;
119 ++mElementsTotal[log_id];
120 }
121
Add(LogStatisticsElement element)122 void LogStatistics::Add(LogStatisticsElement element) {
123 auto lock = std::lock_guard{lock_};
124
125 if (!track_total_size_) {
126 element.total_len = element.msg_len;
127 }
128
129 log_id_t log_id = element.log_id;
130 uint16_t size = element.total_len;
131 mSizes[log_id] += size;
132 ++mElements[log_id];
133
134 mSizesTotal[log_id] += size;
135 SizesTotal += size;
136 ++mElementsTotal[log_id];
137
138 log_time stamp(element.realtime);
139 if (mNewest[log_id] < stamp) {
140 // A major time update invalidates the statistics :-(
141 log_time diff = stamp - mNewest[log_id];
142 mNewest[log_id] = stamp;
143
144 if (diff.tv_sec > hourSec) {
145 // approximate Do-Your-Best fixup
146 diff += mOldest[log_id];
147 if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
148 diff = stamp;
149 }
150 if (diff <= stamp) {
151 mOldest[log_id] = diff;
152 }
153 }
154 }
155
156 if (log_id == LOG_ID_KERNEL) {
157 return;
158 }
159
160 uidTable[log_id].Add(element.uid, element);
161 if (element.uid == AID_SYSTEM) {
162 pidSystemTable[log_id].Add(element.pid, element);
163 }
164
165 if (!enable) {
166 return;
167 }
168
169 pidTable.Add(element.pid, element);
170 tidTable.Add(element.tid, element);
171
172 uint32_t tag = element.tag;
173 if (tag) {
174 if (log_id == LOG_ID_SECURITY) {
175 securityTagTable.Add(tag, element);
176 } else {
177 tagTable.Add(tag, element);
178 }
179 }
180
181 tagNameTable.Add(TagNameKey(element), element);
182 }
183
Subtract(LogStatisticsElement element)184 void LogStatistics::Subtract(LogStatisticsElement element) {
185 auto lock = std::lock_guard{lock_};
186
187 if (!track_total_size_) {
188 element.total_len = element.msg_len;
189 }
190
191 log_id_t log_id = element.log_id;
192 uint16_t size = element.total_len;
193 mSizes[log_id] -= size;
194 --mElements[log_id];
195
196 if (mOldest[log_id] < element.realtime) {
197 mOldest[log_id] = element.realtime;
198 }
199
200 if (log_id == LOG_ID_KERNEL) {
201 return;
202 }
203
204 uidTable[log_id].Subtract(element.uid, element);
205 if (element.uid == AID_SYSTEM) {
206 pidSystemTable[log_id].Subtract(element.pid, element);
207 }
208
209 if (!enable) {
210 return;
211 }
212
213 pidTable.Subtract(element.pid, element);
214 tidTable.Subtract(element.tid, element);
215
216 uint32_t tag = element.tag;
217 if (tag) {
218 if (log_id == LOG_ID_SECURITY) {
219 securityTagTable.Subtract(tag, element);
220 } else {
221 tagTable.Subtract(tag, element);
222 }
223 }
224
225 tagNameTable.Subtract(TagNameKey(element), element);
226 }
227
228 // caller must own and free character string
UidToNameLocked(uid_t uid) const229 const char* LogStatistics::UidToNameLocked(uid_t uid) const {
230 // Local hard coded favourites
231 if (uid == AID_LOGD) {
232 return strdup("auditd");
233 }
234
235 // Android system
236 if (uid < AID_APP) {
237 // in bionic, thread safe as long as we copy the results
238 struct passwd* pwd = getpwuid(uid);
239 if (pwd) {
240 return strdup(pwd->pw_name);
241 }
242 }
243
244 // Parse /data/system/packages.list
245 uid_t userId = uid % AID_USER_OFFSET;
246 const char* name = android::uidToName(userId);
247 if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
248 name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
249 }
250 if (name) {
251 return name;
252 }
253
254 // Android application
255 if (uid >= AID_APP) {
256 struct passwd* pwd = getpwuid(uid);
257 if (pwd) {
258 return strdup(pwd->pw_name);
259 }
260 }
261
262 // report uid -> pid(s) -> pidToName if unique
263 for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
264 ++it) {
265 const PidEntry& entry = it->second;
266
267 if (entry.uid() == uid) {
268 const char* nameTmp = entry.name();
269
270 if (nameTmp) {
271 if (!name) {
272 name = strdup(nameTmp);
273 } else if (fastcmp<strcmp>(name, nameTmp)) {
274 free(const_cast<char*>(name));
275 name = nullptr;
276 break;
277 }
278 }
279 }
280 }
281
282 // No one
283 return name;
284 }
285
286 // Prune at most 10% of the log entries or maxPrune, whichever is less.
ShouldPrune(log_id id,unsigned long max_size,unsigned long * prune_rows) const287 bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
288 unsigned long* prune_rows) const {
289 static constexpr size_t kMinPrune = 4;
290 static constexpr size_t kMaxPrune = 256;
291
292 auto lock = std::lock_guard{lock_};
293 size_t sizes = mSizes[id];
294 if (sizes <= max_size) {
295 return false;
296 }
297 size_t size_over = sizes - ((max_size * 9) / 10);
298 size_t elements = mElements[id];
299 size_t min_elements = elements / 100;
300 if (min_elements < kMinPrune) {
301 min_elements = kMinPrune;
302 }
303 *prune_rows = elements * size_over / sizes;
304 if (*prune_rows < min_elements) {
305 *prune_rows = min_elements;
306 }
307 if (*prune_rows > kMaxPrune) {
308 *prune_rows = kMaxPrune;
309 }
310
311 return true;
312 }
313
formatHeader(const std::string & name,log_id_t id) const314 std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
315 bool isprune = worstUidEnabledForLogid(id);
316 return formatLine(android::base::StringPrintf(name.c_str(),
317 android_log_id_to_name(id)),
318 std::string("Size"),
319 std::string(isprune ? "+/- Pruned" : "")) +
320 formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
321 std::string(isprune ? "NUM" : ""));
322 }
323
324 // Helper to truncate name, if too long, and add name dressings
FormatTmp(const char * nameTmp,uid_t uid,std::string & name,std::string & size,size_t nameLen) const325 void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
326 size_t nameLen) const {
327 const char* allocNameTmp = nullptr;
328 if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
329 if (nameTmp) {
330 size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
331 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
332 lenSpace - 2;
333 size_t lenNameTmp = strlen(nameTmp);
334 while ((len < lenNameTmp) && (lenSpace > 1)) {
335 ++len;
336 --lenSpace;
337 }
338 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
339 if (len < lenNameTmp) {
340 name += "...";
341 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
342 }
343 name += nameTmp;
344 free(const_cast<char*>(allocNameTmp));
345 }
346 }
347
format(const LogStatistics & stat,log_id_t id,uid_t uid) const348 std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
349 REQUIRES(stat.lock_) {
350 std::string name = android::base::StringPrintf("%u", uid);
351 std::string size = android::base::StringPrintf("%zu", getSizes());
352
353 stat.FormatTmp(nullptr, uid, name, size, 6);
354
355 std::string pruned = "";
356 std::string output = formatLine(name, size, pruned);
357
358 if (uid != AID_SYSTEM) {
359 return output;
360 }
361
362 static const size_t maximum_sorted_entries = 32;
363 std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
364 std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
365 stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
366
367 std::string byPid;
368 size_t index;
369 for (index = 0; index < maximum_sorted_entries; ++index) {
370 const PidEntry* entry = sorted_entries[index];
371 if (!entry) {
372 break;
373 }
374 if (entry->getSizes() <= (getSizes() / 100)) {
375 break;
376 }
377 byPid += entry->format(stat, id, *sorted_pids[index]);
378 }
379 if (index > 1) { // print this only if interesting
380 std::string ditto("\" ");
381 output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto, std::string(""));
382 output += byPid;
383 }
384
385 return output;
386 }
387
formatHeader(const std::string & name,log_id_t) const388 std::string PidEntry::formatHeader(const std::string& name,
389 log_id_t /* id */) const {
390 return formatLine(name, std::string("Size"), std::string("Pruned")) +
391 formatLine(std::string(" PID/UID COMMAND LINE"),
392 std::string("BYTES"), std::string("NUM"));
393 }
394
format(const LogStatistics & stat,log_id_t,pid_t pid) const395 std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
396 REQUIRES(stat.lock_) {
397 std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
398 std::string size = android::base::StringPrintf("%zu", getSizes());
399
400 stat.FormatTmp(name_, uid_, name, size, 12);
401
402 std::string pruned = "";
403 return formatLine(name, size, pruned);
404 }
405
formatHeader(const std::string & name,log_id_t) const406 std::string TidEntry::formatHeader(const std::string& name,
407 log_id_t /* id */) const {
408 return formatLine(name, std::string("Size"), std::string("Pruned")) +
409 formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
410 std::string("NUM"));
411 }
412
format(const LogStatistics & stat,log_id_t,pid_t tid) const413 std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
414 REQUIRES(stat.lock_) {
415 std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
416 std::string size = android::base::StringPrintf("%zu", getSizes());
417
418 stat.FormatTmp(name_, uid_, name, size, 12);
419
420 std::string pruned = "";
421 return formatLine(name, size, pruned);
422 }
423
formatHeader(const std::string & name,log_id_t id) const424 std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
425 bool isprune = worstUidEnabledForLogid(id);
426 return formatLine(name, std::string("Size"),
427 std::string(isprune ? "Prune" : "")) +
428 formatLine(std::string(" TAG/UID TAGNAME"),
429 std::string("BYTES"), std::string(isprune ? "NUM" : ""));
430 }
431
format(const LogStatistics &,log_id_t,uint32_t) const432 std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
433 std::string name;
434 if (uid_ == (uid_t)-1) {
435 name = android::base::StringPrintf("%7u", key());
436 } else {
437 name = android::base::StringPrintf("%7u/%u", key(), uid_);
438 }
439 const char* nameTmp = this->name();
440 if (nameTmp) {
441 name += android::base::StringPrintf(
442 "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
443 }
444
445 std::string size = android::base::StringPrintf("%zu", getSizes());
446
447 std::string pruned = "";
448 return formatLine(name, size, pruned);
449 }
450
formatHeader(const std::string & name,log_id_t) const451 std::string TagNameEntry::formatHeader(const std::string& name,
452 log_id_t /* id */) const {
453 return formatLine(name, std::string("Size"), std::string("")) +
454 formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
455 std::string("BYTES"), std::string(""));
456 }
457
format(const LogStatistics &,log_id_t,const std::string & key_name) const458 std::string TagNameEntry::format(const LogStatistics&, log_id_t,
459 const std::string& key_name) const {
460 std::string name;
461 std::string pidstr;
462 if (pid_ != (pid_t)-1) {
463 pidstr = android::base::StringPrintf("%u", pid_);
464 if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
465 }
466 int len = 9 - pidstr.length();
467 if (len < 0) len = 0;
468 if (tid_ == (pid_t)-1 || tid_ == pid_) {
469 name = android::base::StringPrintf("%*s", len, "");
470 } else {
471 name = android::base::StringPrintf("%*u", len, tid_);
472 }
473 name += pidstr;
474 if (uid_ != (uid_t)-1) {
475 name += android::base::StringPrintf("/%u", uid_);
476 }
477
478 std::string size = android::base::StringPrintf("%zu", getSizes());
479
480 const char* nameTmp = key_name.data();
481 if (nameTmp) {
482 size_t lenSpace = std::max(16 - name.length(), (size_t)1);
483 size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
484 lenSpace - 2;
485 size_t lenNameTmp = strlen(nameTmp);
486 while ((len < lenNameTmp) && (lenSpace > 1)) {
487 ++len;
488 --lenSpace;
489 }
490 name += android::base::StringPrintf("%*s", (int)lenSpace, "");
491 if (len < lenNameTmp) {
492 name += "...";
493 nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
494 }
495 name += nameTmp;
496 }
497
498 std::string pruned = "";
499
500 return formatLine(name, size, pruned);
501 }
502
formatMsec(uint64_t val)503 static std::string formatMsec(uint64_t val) {
504 static const unsigned subsecDigits = 3;
505 static const uint64_t sec = MS_PER_SEC;
506
507 static const uint64_t minute = 60 * sec;
508 static const uint64_t hour = 60 * minute;
509 static const uint64_t day = 24 * hour;
510
511 std::string output;
512 if (val < sec) return output;
513
514 if (val >= day) {
515 output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
516 val = (val % day) + day;
517 }
518 if (val >= minute) {
519 if (val >= hour) {
520 output += android::base::StringPrintf("%" PRIu64 ":",
521 (val / hour) % (day / hour));
522 }
523 output += android::base::StringPrintf(
524 (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
525 (val / minute) % (hour / minute));
526 }
527 output +=
528 android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
529 (val / sec) % (minute / sec));
530 val %= sec;
531 unsigned digits = subsecDigits;
532 while (digits && ((val % 10) == 0)) {
533 val /= 10;
534 --digits;
535 }
536 if (digits) {
537 output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
538 }
539 return output;
540 }
541
542 template <typename TKey, typename TEntry>
FormatTable(const LogHashtable<TKey,TEntry> & table,uid_t uid,pid_t pid,const std::string & name,log_id_t id) const543 std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
544 pid_t pid, const std::string& name, log_id_t id) const
545 REQUIRES(lock_) {
546 static const size_t maximum_sorted_entries = 32;
547 std::string output;
548 std::array<const TKey*, maximum_sorted_entries> sorted_keys;
549 std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
550 table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
551 bool header_printed = false;
552 for (size_t index = 0; index < maximum_sorted_entries; ++index) {
553 const TEntry* entry = sorted_entries[index];
554 if (!entry) {
555 break;
556 }
557 if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
558 break;
559 }
560 if (!header_printed) {
561 output += "\n\n";
562 output += entry->formatHeader(name, id);
563 header_printed = true;
564 }
565 output += entry->format(*this, id, *sorted_keys[index]);
566 }
567 return output;
568 }
569
ReportInteresting() const570 std::string LogStatistics::ReportInteresting() const {
571 auto lock = std::lock_guard{lock_};
572
573 std::vector<std::string> items;
574
575 log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
576
577 log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
578
579 log_id_for_each(i) {
580 items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
581 }
582
583 log_id_for_each(i) {
584 uint64_t oldest = mOldest[i].msec() / 1000;
585 uint64_t newest = mNewest[i].msec() / 1000;
586
587 int span = newest - oldest;
588
589 items.emplace_back(std::to_string(span));
590 }
591
592 return android::base::Join(items, ",");
593 }
594
Format(uid_t uid,pid_t pid,unsigned int logMask) const595 std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
596 auto lock = std::lock_guard{lock_};
597
598 static const uint16_t spaces_total = 19;
599
600 // Report on total logging, current and for all time
601
602 std::string output = "size/num";
603 size_t oldLength;
604 int16_t spaces = 1;
605
606 log_id_for_each(id) {
607 if (!(logMask & (1 << id))) continue;
608 oldLength = output.length();
609 if (spaces < 0) spaces = 0;
610 output += android::base::StringPrintf("%*s%s", spaces, "",
611 android_log_id_to_name(id));
612 spaces += spaces_total + oldLength - output.length();
613 }
614 if (spaces < 0) spaces = 0;
615 output += android::base::StringPrintf("%*sTotal", spaces, "");
616
617 static const char TotalStr[] = "\nTotal";
618 spaces = 10 - strlen(TotalStr);
619 output += TotalStr;
620
621 size_t totalSize = 0;
622 size_t totalEls = 0;
623 log_id_for_each(id) {
624 if (!(logMask & (1 << id))) continue;
625 oldLength = output.length();
626 if (spaces < 0) spaces = 0;
627 size_t szs = mSizesTotal[id];
628 totalSize += szs;
629 size_t els = mElementsTotal[id];
630 totalEls += els;
631 output +=
632 android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
633 spaces += spaces_total + oldLength - output.length();
634 }
635 if (spaces < 0) spaces = 0;
636 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
637 totalEls);
638
639 static const char NowStr[] = "\nNow";
640 spaces = 10 - strlen(NowStr);
641 output += NowStr;
642
643 totalSize = 0;
644 totalEls = 0;
645 log_id_for_each(id) {
646 if (!(logMask & (1 << id))) continue;
647
648 size_t els = mElements[id];
649 oldLength = output.length();
650 if (spaces < 0) spaces = 0;
651 size_t szs = mSizes[id];
652 totalSize += szs;
653 totalEls += els;
654 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
655 spaces -= output.length() - oldLength;
656 spaces += spaces_total;
657 }
658 if (spaces < 0) spaces = 0;
659 output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
660 totalEls);
661
662 static const char SpanStr[] = "\nLogspan";
663 spaces = 10 - strlen(SpanStr);
664 output += SpanStr;
665
666 // Total reports the greater of the individual maximum time span, or the
667 // validated minimum start and maximum end time span if it makes sense.
668 uint64_t minTime = UINT64_MAX;
669 uint64_t maxTime = 0;
670 uint64_t maxSpan = 0;
671 totalSize = 0;
672
673 log_id_for_each(id) {
674 if (!(logMask & (1 << id))) continue;
675
676 // validity checking
677 uint64_t oldest = mOldest[id].msec();
678 uint64_t newest = mNewest[id].msec();
679 if (newest <= oldest) {
680 spaces += spaces_total;
681 continue;
682 }
683
684 uint64_t span = newest - oldest;
685 if (span > (monthSec * MS_PER_SEC)) {
686 spaces += spaces_total;
687 continue;
688 }
689
690 // total span
691 if (minTime > oldest) minTime = oldest;
692 if (maxTime < newest) maxTime = newest;
693 if (span > maxSpan) maxSpan = span;
694 totalSize += span;
695
696 oldLength = output.length();
697 output += android::base::StringPrintf("%*s%s", spaces, "", formatMsec(span).c_str());
698 spaces -= output.length() - oldLength;
699 spaces += spaces_total;
700 }
701 if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
702 (maxTime > maxSpan)) {
703 maxSpan = maxTime;
704 }
705 if (spaces < 0) spaces = 0;
706 output += android::base::StringPrintf("%*s%s", spaces, "",
707 formatMsec(maxSpan).c_str());
708
709 static const char OverheadStr[] = "\nOverhead";
710 spaces = 10 - strlen(OverheadStr);
711 output += OverheadStr;
712
713 totalSize = 0;
714 log_id_for_each(id) {
715 if (!(logMask & (1 << id))) continue;
716
717 size_t els = mElements[id];
718 if (els) {
719 oldLength = output.length();
720 if (spaces < 0) spaces = 0;
721 size_t szs = 0;
722 if (overhead_[id]) {
723 szs = *overhead_[id];
724 } else {
725 CHECK(track_total_size_);
726 szs = mSizes[id];
727 }
728 totalSize += szs;
729 output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
730 spaces -= output.length() - oldLength;
731 }
732 spaces += spaces_total;
733 }
734 totalSize += sizeOf();
735 if (spaces < 0) spaces = 0;
736 output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
737
738 // Report on Chattiest
739
740 std::string name;
741
742 // Chattiest by application (UID)
743 log_id_for_each(id) {
744 if (!(logMask & (1 << id))) continue;
745
746 name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
747 : "Logging for your UID in %s log buffer:";
748 output += FormatTable(uidTable[id], uid, pid, name, id);
749 }
750
751 if (enable) {
752 name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
753 : "Logging for this PID:";
754 output += FormatTable(pidTable, uid, pid, name);
755 name = "Chattiest TIDs";
756 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
757 name += ":";
758 output += FormatTable(tidTable, uid, pid, name);
759 }
760
761 if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
762 name = "Chattiest events log buffer TAGs";
763 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
764 name += ":";
765 output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
766 }
767
768 if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
769 name = "Chattiest security log buffer TAGs";
770 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
771 name += ":";
772 output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
773 }
774
775 if (enable) {
776 name = "Chattiest TAGs";
777 if (pid) name += android::base::StringPrintf(" for PID %d", pid);
778 name += ":";
779 output += FormatTable(tagNameTable, uid, pid, name);
780 }
781
782 return output;
783 }
784
785 namespace android {
786
pidToUid(pid_t pid)787 uid_t pidToUid(pid_t pid) {
788 char path[32];
789 snprintf(path, sizeof(path), "/proc/%u", pid);
790 struct stat sb;
791 return !stat(path, &sb) ? sb.st_uid : AID_LOGD;
792 }
793
794 }
795
PidToUid(pid_t pid)796 uid_t LogStatistics::PidToUid(pid_t pid) {
797 auto lock = std::lock_guard{lock_};
798 return pidTable.Add(pid)->second.uid();
799 }
800
801 // caller must free character string
PidToName(pid_t pid) const802 const char* LogStatistics::PidToName(pid_t pid) const {
803 auto lock = std::lock_guard{lock_};
804 // An inconvenient truth ... getName() can alter the object
805 pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
806 const char* name = writablePidTable.Add(pid)->second.name();
807 if (!name) {
808 return nullptr;
809 }
810 return strdup(name);
811 }
812