Home | History | Annotate | Download | only in logd
      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 
     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 
     53 size_t sizesTotal() {
     54     return LogStatistics::sizesTotal();
     55 }
     56 
     57 // caller must own and free character string
     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 
     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 
     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 
    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.
    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
    243 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 
    300 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
    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 
    335 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 
    436 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 
    443 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 
    461 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 
    468 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 
    485 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 
    493 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 
    519 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 
    526 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 
    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 
    614 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 
    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 
    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 
    861 uid_t LogStatistics::pidToUid(pid_t pid) {
    862     return pidTable.add(pid)->second.getUid();
    863 }
    864 
    865 pid_t LogStatistics::tidToPid(pid_t tid) {
    866     return tidTable.add(tid)->second.getPid();
    867 }
    868 
    869 // caller must free character string
    870 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