• 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/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