• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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