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