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