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 <fcntl.h>
     18 #include <stdarg.h>
     19 #include <time.h>
     20 
     21 #include <log/logger.h>
     22 #include <private/android_filesystem_config.h>
     23 #include <utils/String8.h>
     24 
     25 #include "LogStatistics.h"
     26 
     27 PidStatistics::PidStatistics(pid_t pid, char *name)
     28         : pid(pid)
     29         , mSizesTotal(0)
     30         , mElementsTotal(0)
     31         , mSizes(0)
     32         , mElements(0)
     33         , name(name)
     34         , mGone(false)
     35 { }
     36 
     37 #ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
     38 PidStatistics::PidStatistics(const PidStatistics &copy)
     39         : pid(copy->pid)
     40         , name(copy->name ? strdup(copy->name) : NULL)
     41         , mSizesTotal(copy->mSizesTotal)
     42         , mElementsTotal(copy->mElementsTotal)
     43         , mSizes(copy->mSizes)
     44         , mElements(copy->mElements)
     45         , mGone(copy->mGone)
     46 { }
     47 #endif
     48 
     49 PidStatistics::~PidStatistics() {
     50     free(name);
     51 }
     52 
     53 bool PidStatistics::pidGone() {
     54     if (mGone || (pid == gone)) {
     55         return true;
     56     }
     57     if (pid == 0) {
     58         return false;
     59     }
     60     if (kill(pid, 0) && (errno != EPERM)) {
     61         mGone = true;
     62         return true;
     63     }
     64     return false;
     65 }
     66 
     67 void PidStatistics::setName(char *new_name) {
     68     free(name);
     69     name = new_name;
     70 }
     71 
     72 void PidStatistics::add(unsigned short size) {
     73     mSizesTotal += size;
     74     ++mElementsTotal;
     75     mSizes += size;
     76     ++mElements;
     77 }
     78 
     79 bool PidStatistics::subtract(unsigned short size) {
     80     mSizes -= size;
     81     --mElements;
     82     return (mElements == 0) && pidGone();
     83 }
     84 
     85 void PidStatistics::addTotal(size_t size, size_t element) {
     86     if (pid == gone) {
     87         mSizesTotal += size;
     88         mElementsTotal += element;
     89     }
     90 }
     91 
     92 // must call free to release return value
     93 //  If only we could sniff our own logs for:
     94 //   <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
     95 //  which debuggerd prints as a process is crashing.
     96 char *PidStatistics::pidToName(pid_t pid) {
     97     char *retval = NULL;
     98     if (pid == 0) { // special case from auditd for kernel
     99         retval = strdup("logd.auditd");
    100     } else if (pid != gone) {
    101         char buffer[512];
    102         snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
    103         int fd = open(buffer, O_RDONLY);
    104         if (fd >= 0) {
    105             ssize_t ret = read(fd, buffer, sizeof(buffer));
    106             if (ret > 0) {
    107                 buffer[sizeof(buffer)-1] = '\0';
    108                 // frameworks intermediate state
    109                 if (strcmp(buffer, "<pre-initialized>")) {
    110                     retval = strdup(buffer);
    111                 }
    112             }
    113             close(fd);
    114         }
    115     }
    116     return retval;
    117 }
    118 
    119 UidStatistics::UidStatistics(uid_t uid)
    120         : uid(uid)
    121         , mSizes(0)
    122         , mElements(0) {
    123     Pids.clear();
    124 }
    125 
    126 UidStatistics::~UidStatistics() {
    127     PidStatisticsCollection::iterator it;
    128     for (it = begin(); it != end();) {
    129         delete (*it);
    130         it = erase(it);
    131     }
    132 }
    133 
    134 void UidStatistics::add(unsigned short size, pid_t pid) {
    135     mSizes += size;
    136     ++mElements;
    137 
    138     PidStatistics *p = NULL;
    139     PidStatisticsCollection::iterator last;
    140     PidStatisticsCollection::iterator it;
    141     for (last = it = begin(); it != end(); last = it, ++it) {
    142         p = *it;
    143         if (pid == p->getPid()) {
    144             p->add(size);
    145             return;
    146         }
    147     }
    148     // insert if the gone entry.
    149     bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
    150     p = new PidStatistics(pid, pidToName(pid));
    151     if (insert_before_last) {
    152         insert(last, p);
    153     } else {
    154         push_back(p);
    155     }
    156     p->add(size);
    157 }
    158 
    159 void UidStatistics::subtract(unsigned short size, pid_t pid) {
    160     mSizes -= size;
    161     --mElements;
    162 
    163     PidStatisticsCollection::iterator it;
    164     for (it = begin(); it != end(); ++it) {
    165         PidStatistics *p = *it;
    166         if (pid == p->getPid()) {
    167             if (p->subtract(size)) {
    168                 size_t szsTotal = p->sizesTotal();
    169                 size_t elsTotal = p->elementsTotal();
    170                 delete p;
    171                 erase(it);
    172                 it = end();
    173                 --it;
    174                 if (it == end()) {
    175                     p = new PidStatistics(p->gone);
    176                     push_back(p);
    177                 } else {
    178                     p = *it;
    179                     if (p->getPid() != p->gone) {
    180                         p = new PidStatistics(p->gone);
    181                         push_back(p);
    182                     }
    183                 }
    184                 p->addTotal(szsTotal, elsTotal);
    185             }
    186             return;
    187         }
    188     }
    189 }
    190 
    191 void UidStatistics::sort() {
    192     for (bool pass = true; pass;) {
    193         pass = false;
    194         PidStatisticsCollection::iterator it = begin();
    195         if (it != end()) {
    196             PidStatisticsCollection::iterator lt = it;
    197             PidStatistics *l = (*lt);
    198             while (++it != end()) {
    199                 PidStatistics *n = (*it);
    200                 if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
    201                     pass = true;
    202                     erase(it);
    203                     insert(lt, n);
    204                     it = lt;
    205                     n = l;
    206                 }
    207                 lt = it;
    208                 l = n;
    209             }
    210         }
    211     }
    212 }
    213 
    214 size_t UidStatistics::sizes(pid_t pid) {
    215     if (pid == pid_all) {
    216         return sizes();
    217     }
    218 
    219     PidStatisticsCollection::iterator it;
    220     for (it = begin(); it != end(); ++it) {
    221         PidStatistics *p = *it;
    222         if (pid == p->getPid()) {
    223             return p->sizes();
    224         }
    225     }
    226     return 0;
    227 }
    228 
    229 size_t UidStatistics::elements(pid_t pid) {
    230     if (pid == pid_all) {
    231         return elements();
    232     }
    233 
    234     PidStatisticsCollection::iterator it;
    235     for (it = begin(); it != end(); ++it) {
    236         PidStatistics *p = *it;
    237         if (pid == p->getPid()) {
    238             return p->elements();
    239         }
    240     }
    241     return 0;
    242 }
    243 
    244 size_t UidStatistics::sizesTotal(pid_t pid) {
    245     size_t sizes = 0;
    246     PidStatisticsCollection::iterator it;
    247     for (it = begin(); it != end(); ++it) {
    248         PidStatistics *p = *it;
    249         if ((pid == pid_all) || (pid == p->getPid())) {
    250             sizes += p->sizesTotal();
    251         }
    252     }
    253     return sizes;
    254 }
    255 
    256 size_t UidStatistics::elementsTotal(pid_t pid) {
    257     size_t elements = 0;
    258     PidStatisticsCollection::iterator it;
    259     for (it = begin(); it != end(); ++it) {
    260         PidStatistics *p = *it;
    261         if ((pid == pid_all) || (pid == p->getPid())) {
    262             elements += p->elementsTotal();
    263         }
    264     }
    265     return elements;
    266 }
    267 
    268 LidStatistics::LidStatistics() {
    269     Uids.clear();
    270 }
    271 
    272 LidStatistics::~LidStatistics() {
    273     UidStatisticsCollection::iterator it;
    274     for (it = begin(); it != end();) {
    275         delete (*it);
    276         it = Uids.erase(it);
    277     }
    278 }
    279 
    280 void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
    281     UidStatistics *u;
    282     UidStatisticsCollection::iterator it;
    283     UidStatisticsCollection::iterator last;
    284 
    285     if (uid == (uid_t) -1) { // init
    286         uid = (uid_t) AID_ROOT;
    287     }
    288 
    289     for (last = it = begin(); it != end(); last = it, ++it) {
    290         u = *it;
    291         if (uid == u->getUid()) {
    292             u->add(size, pid);
    293             if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
    294                 Uids.erase(it);
    295                 Uids.insert(last, u);
    296             }
    297             return;
    298         }
    299     }
    300     u = new UidStatistics(uid);
    301     if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
    302         Uids.insert(last, u);
    303     } else {
    304         Uids.push_back(u);
    305     }
    306     u->add(size, pid);
    307 }
    308 
    309 void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
    310     if (uid == (uid_t) -1) { // init
    311         uid = (uid_t) AID_ROOT;
    312     }
    313 
    314     UidStatisticsCollection::iterator it;
    315     for (it = begin(); it != end(); ++it) {
    316         UidStatistics *u = *it;
    317         if (uid == u->getUid()) {
    318             u->subtract(size, pid);
    319             return;
    320         }
    321     }
    322 }
    323 
    324 void LidStatistics::sort() {
    325     for (bool pass = true; pass;) {
    326         pass = false;
    327         UidStatisticsCollection::iterator it = begin();
    328         if (it != end()) {
    329             UidStatisticsCollection::iterator lt = it;
    330             UidStatistics *l = (*lt);
    331             while (++it != end()) {
    332                 UidStatistics *n = (*it);
    333                 if (n->sizes() > l->sizes()) {
    334                     pass = true;
    335                     Uids.erase(it);
    336                     Uids.insert(lt, n);
    337                     it = lt;
    338                     n = l;
    339                 }
    340                 lt = it;
    341                 l = n;
    342             }
    343         }
    344     }
    345 }
    346 
    347 size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
    348     size_t sizes = 0;
    349     UidStatisticsCollection::iterator it;
    350     for (it = begin(); it != end(); ++it) {
    351         UidStatistics *u = *it;
    352         if ((uid == uid_all) || (uid == u->getUid())) {
    353             sizes += u->sizes(pid);
    354         }
    355     }
    356     return sizes;
    357 }
    358 
    359 size_t LidStatistics::elements(uid_t uid, pid_t pid) {
    360     size_t elements = 0;
    361     UidStatisticsCollection::iterator it;
    362     for (it = begin(); it != end(); ++it) {
    363         UidStatistics *u = *it;
    364         if ((uid == uid_all) || (uid == u->getUid())) {
    365             elements += u->elements(pid);
    366         }
    367     }
    368     return elements;
    369 }
    370 
    371 size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
    372     size_t sizes = 0;
    373     UidStatisticsCollection::iterator it;
    374     for (it = begin(); it != end(); ++it) {
    375         UidStatistics *u = *it;
    376         if ((uid == uid_all) || (uid == u->getUid())) {
    377             sizes += u->sizesTotal(pid);
    378         }
    379     }
    380     return sizes;
    381 }
    382 
    383 size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
    384     size_t elements = 0;
    385     UidStatisticsCollection::iterator it;
    386     for (it = begin(); it != end(); ++it) {
    387         UidStatistics *u = *it;
    388         if ((uid == uid_all) || (uid == u->getUid())) {
    389             elements += u->elementsTotal(pid);
    390         }
    391     }
    392     return elements;
    393 }
    394 
    395 LogStatistics::LogStatistics()
    396         : mStatistics(false)
    397         , dgramQlenStatistics(false)
    398         , start(CLOCK_MONOTONIC) {
    399     log_id_for_each(i) {
    400         mSizes[i] = 0;
    401         mElements[i] = 0;
    402     }
    403 
    404     for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
    405         mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
    406         mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
    407     }
    408 }
    409 
    410 //   Each bucket below represents a dgramQlen of log messages. By
    411 //   finding the minimum period of time from start to finish
    412 //   of each dgramQlen, we can get a performance expectation for
    413 //   the user space logger. The net result is that the period
    414 //   of time divided by the dgramQlen will give us the average time
    415 //   between log messages; at the point where the average time
    416 //   is greater than the throughput capability of the logger
    417 //   we will not longer require the benefits of the FIFO formed
    418 //   by max_dgram_qlen. We will also expect to see a very visible
    419 //   knee in the average time between log messages at this point,
    420 //   so we do not necessarily have to compare the rate against the
    421 //   measured performance (BM_log_maximum_retry) of the logger.
    422 //
    423 //   for example (reformatted):
    424 //
    425 //       Minimum time between log events per dgramQlen:
    426 //       1   2   3   5   10  20  30  50  100  200 300 400 500 600
    427 //       5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
    428 //
    429 //   demonstrates a clear knee rising at 100, so this means that for this
    430 //   case max_dgram_qlen = 100 would be more than sufficient to handle the
    431 //   worst that the system could stuff into the logger. The
    432 //   BM_log_maximum_retry performance (derated by the log collection) on the
    433 //   same system was 33.2us so we would almost be fine with max_dgram_qlen = 50.
    434 //   BM_log_maxumum_retry with statistics off is roughly 20us, so
    435 //   max_dgram_qlen = 20 would work. We will be more than willing to have
    436 //   a large engineering margin so the rule of thumb that lead us to 100 is
    437 //   fine.
    438 //
    439 // bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
    440 const unsigned short LogStatistics::mBuckets[] = {
    441     1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
    442 };
    443 
    444 unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
    445     if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
    446         return 0;
    447     }
    448     return mBuckets[bucket];
    449 }
    450 
    451 unsigned long long LogStatistics::minimum(unsigned short bucket) {
    452     if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) {
    453         return 0;
    454     }
    455     return mMinimum[bucket].nsec();
    456 }
    457 
    458 void LogStatistics::recordDiff(log_time diff, unsigned short bucket) {
    459     if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) {
    460         mMinimum[bucket] = diff;
    461     }
    462 }
    463 
    464 void LogStatistics::add(unsigned short size,
    465                         log_id_t log_id, uid_t uid, pid_t pid) {
    466     mSizes[log_id] += size;
    467     ++mElements[log_id];
    468     if (!mStatistics) {
    469         return;
    470     }
    471     id(log_id).add(size, uid, pid);
    472 }
    473 
    474 void LogStatistics::subtract(unsigned short size,
    475                              log_id_t log_id, uid_t uid, pid_t pid) {
    476     mSizes[log_id] -= size;
    477     --mElements[log_id];
    478     if (!mStatistics) {
    479         return;
    480     }
    481     id(log_id).subtract(size, uid, pid);
    482 }
    483 
    484 size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
    485     if (log_id != log_id_all) {
    486         return id(log_id).sizes(uid, pid);
    487     }
    488     size_t sizes = 0;
    489     log_id_for_each(i) {
    490         sizes += id(i).sizes(uid, pid);
    491     }
    492     return sizes;
    493 }
    494 
    495 size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
    496     if (log_id != log_id_all) {
    497         return id(log_id).elements(uid, pid);
    498     }
    499     size_t elements = 0;
    500     log_id_for_each(i) {
    501         elements += id(i).elements(uid, pid);
    502     }
    503     return elements;
    504 }
    505 
    506 size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
    507     if (log_id != log_id_all) {
    508         return id(log_id).sizesTotal(uid, pid);
    509     }
    510     size_t sizes = 0;
    511     log_id_for_each(i) {
    512         sizes += id(i).sizesTotal(uid, pid);
    513     }
    514     return sizes;
    515 }
    516 
    517 size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
    518     if (log_id != log_id_all) {
    519         return id(log_id).elementsTotal(uid, pid);
    520     }
    521     size_t elements = 0;
    522     log_id_for_each(i) {
    523         elements += id(i).elementsTotal(uid, pid);
    524     }
    525     return elements;
    526 }
    527 
    528 void LogStatistics::format(char **buf,
    529                            uid_t uid, unsigned int logMask, log_time oldest) {
    530     static const unsigned short spaces_current = 13;
    531     static const unsigned short spaces_total = 19;
    532 
    533     if (*buf) {
    534         free(*buf);
    535         *buf = NULL;
    536     }
    537 
    538     android::String8 string("        span -> size/num");
    539     size_t oldLength;
    540     short spaces = 2;
    541 
    542     log_id_for_each(i) {
    543         if (!(logMask & (1 << i))) {
    544             continue;
    545         }
    546         oldLength = string.length();
    547         if (spaces < 0) {
    548             spaces = 0;
    549         }
    550         string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
    551         spaces += spaces_total + oldLength - string.length();
    552 
    553         LidStatistics &l = id(i);
    554         l.sort();
    555 
    556         UidStatisticsCollection::iterator iu;
    557         for (iu = l.begin(); iu != l.end(); ++iu) {
    558             (*iu)->sort();
    559         }
    560     }
    561 
    562     spaces = 1;
    563     log_time t(CLOCK_MONOTONIC);
    564     unsigned long long d;
    565     if (mStatistics) {
    566         d = t.nsec() - start.nsec();
    567         string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
    568                   d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
    569                   (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
    570 
    571         log_id_for_each(i) {
    572             if (!(logMask & (1 << i))) {
    573                 continue;
    574             }
    575             oldLength = string.length();
    576             if (spaces < 0) {
    577                 spaces = 0;
    578             }
    579             string.appendFormat("%*s%zu/%zu", spaces, "",
    580                                 sizesTotal(i), elementsTotal(i));
    581             spaces += spaces_total + oldLength - string.length();
    582         }
    583         spaces = 1;
    584     }
    585 
    586     d = t.nsec() - oldest.nsec();
    587     string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
    588                   d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
    589                   (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
    590 
    591     log_id_for_each(i) {
    592         if (!(logMask & (1 << i))) {
    593             continue;
    594         }
    595 
    596         size_t els = elements(i);
    597         if (els) {
    598             oldLength = string.length();
    599             if (spaces < 0) {
    600                 spaces = 0;
    601             }
    602             string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
    603             spaces -= string.length() - oldLength;
    604         }
    605         spaces += spaces_total;
    606     }
    607 
    608     // Construct list of worst spammers by Pid
    609     static const unsigned char num_spammers = 10;
    610     bool header = false;
    611 
    612     log_id_for_each(i) {
    613         if (!(logMask & (1 << i))) {
    614             continue;
    615         }
    616 
    617         PidStatisticsCollection pids;
    618         pids.clear();
    619 
    620         LidStatistics &l = id(i);
    621         UidStatisticsCollection::iterator iu;
    622         for (iu = l.begin(); iu != l.end(); ++iu) {
    623             UidStatistics &u = *(*iu);
    624             PidStatisticsCollection::iterator ip;
    625             for (ip = u.begin(); ip != u.end(); ++ip) {
    626                 PidStatistics *p = (*ip);
    627                 if (p->getPid() == p->gone) {
    628                     break;
    629                 }
    630 
    631                 size_t mySizes = p->sizes();
    632 
    633                 PidStatisticsCollection::iterator q;
    634                 unsigned char num = 0;
    635                 for (q = pids.begin(); q != pids.end(); ++q) {
    636                     if (mySizes > (*q)->sizes()) {
    637                         pids.insert(q, p);
    638                         break;
    639                     }
    640                     // do we need to traverse deeper in the list?
    641                     if (++num > num_spammers) {
    642                         break;
    643                     }
    644                 }
    645                 if (q == pids.end()) {
    646                    pids.push_back(p);
    647                 }
    648             }
    649         }
    650 
    651         size_t threshold = sizes(i);
    652         if (threshold < 65536) {
    653             threshold = 65536;
    654         }
    655         threshold /= 100;
    656 
    657         PidStatisticsCollection::iterator pt = pids.begin();
    658 
    659         for(int line = 0;
    660                 (pt != pids.end()) && (line < num_spammers);
    661                 ++line, pt = pids.erase(pt)) {
    662             PidStatistics *p = *pt;
    663 
    664             size_t sizes = p->sizes();
    665             if (sizes < threshold) {
    666                 break;
    667             }
    668 
    669             char *name = p->getName();
    670             pid_t pid = p->getPid();
    671             if (!name || !*name) {
    672                 name = pidToName(pid);
    673                 if (name) {
    674                     if (*name) {
    675                         p->setName(name);
    676                     } else {
    677                         free(name);
    678                         name = NULL;
    679                     }
    680                 }
    681             }
    682 
    683             if (!header) {
    684                 string.appendFormat("\n\nChattiest clients:\n"
    685                                     "log id %-*s PID[?] name",
    686                                     spaces_total, "size/total");
    687                 header = true;
    688             }
    689 
    690             size_t sizesTotal = p->sizesTotal();
    691 
    692             android::String8 sz("");
    693             sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
    694                             sizes, sizesTotal);
    695 
    696             android::String8 pd("");
    697             pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
    698 
    699             string.appendFormat("\n%-7s%-*s %-7s%s",
    700                                 line ? "" : android_log_id_to_name(i),
    701                                 spaces_total, sz.string(), pd.string(),
    702                                 name ? name : "");
    703         }
    704 
    705         pids.clear();
    706     }
    707 
    708     if (dgramQlenStatistics) {
    709         const unsigned short spaces_time = 6;
    710         const unsigned long long max_seconds = 100000;
    711         spaces = 0;
    712         string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
    713         for(unsigned short i = 0; dgramQlen(i); ++i) {
    714             oldLength = string.length();
    715             if (spaces < 0) {
    716                 spaces = 0;
    717             }
    718             string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
    719             spaces += spaces_time + oldLength - string.length();
    720         }
    721         string.append("\n");
    722         spaces = 0;
    723         unsigned short n;
    724         for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
    725             unsigned long long duration = minimum(i);
    726             if (duration) {
    727                 duration /= n;
    728                 if (duration >= (NS_PER_SEC * max_seconds)) {
    729                     duration = NS_PER_SEC * (max_seconds - 1);
    730                 }
    731                 oldLength = string.length();
    732                 if (spaces < 0) {
    733                     spaces = 0;
    734                 }
    735                 string.appendFormat("%*s", spaces, "");
    736                 if (duration >= (NS_PER_SEC * 10)) {
    737                     string.appendFormat("%llu",
    738                         (duration + (NS_PER_SEC / 2))
    739                             / NS_PER_SEC);
    740                 } else if (duration >= (NS_PER_SEC / (1000 / 10))) {
    741                     string.appendFormat("%llum",
    742                         (duration + (NS_PER_SEC / 2 / 1000))
    743                             / (NS_PER_SEC / 1000));
    744                 } else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
    745                     string.appendFormat("%lluu",
    746                         (duration + (NS_PER_SEC / 2 / 1000000))
    747                             / (NS_PER_SEC / 1000000));
    748                 } else {
    749                     string.appendFormat("%llun", duration);
    750                 }
    751                 spaces -= string.length() - oldLength;
    752             }
    753             spaces += spaces_time;
    754         }
    755     }
    756 
    757     log_id_for_each(i) {
    758         if (!(logMask & (1 << i))) {
    759             continue;
    760         }
    761 
    762         header = false;
    763         bool first = true;
    764 
    765         UidStatisticsCollection::iterator ut;
    766         for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
    767             UidStatistics *up = *ut;
    768             if ((uid != AID_ROOT) && (uid != up->getUid())) {
    769                 continue;
    770             }
    771 
    772             PidStatisticsCollection::iterator pt = up->begin();
    773             if (pt == up->end()) {
    774                 continue;
    775             }
    776 
    777             android::String8 intermediate;
    778 
    779             if (!header) {
    780                 // header below tuned to match spaces_total and spaces_current
    781                 spaces = 0;
    782                 intermediate = string.format("%s: UID/PID Total size/num",
    783                                              android_log_id_to_name(i));
    784                 string.appendFormat("\n\n%-31sNow          "
    785                                          "UID/PID[?]  Total              Now",
    786                                     intermediate.string());
    787                 intermediate.clear();
    788                 header = true;
    789             }
    790 
    791             bool oneline = ++pt == up->end();
    792             --pt;
    793 
    794             if (!oneline) {
    795                 first = true;
    796             } else if (!first && (spaces > 0)) {
    797                 string.appendFormat("%*s", spaces, "");
    798             }
    799             spaces = 0;
    800 
    801             uid_t u = up->getUid();
    802             PidStatistics *pp = *pt;
    803             pid_t p = pp->getPid();
    804 
    805             intermediate = string.format(oneline
    806                                              ? ((p == PidStatistics::gone)
    807                                                  ? "%d/?"
    808                                                  : "%d/%d%c")
    809                                              : "%d",
    810                                          u, p, pp->pidGone() ? '?' : '\0');
    811             string.appendFormat(first ? "\n%-12s" : "%-12s",
    812                                 intermediate.string());
    813             intermediate.clear();
    814 
    815             size_t elsTotal = up->elementsTotal();
    816             oldLength = string.length();
    817             string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
    818             spaces += spaces_total + oldLength - string.length();
    819 
    820             size_t els = up->elements();
    821             if (els == elsTotal) {
    822                 if (spaces < 0) {
    823                     spaces = 0;
    824                 }
    825                 string.appendFormat("%*s=", spaces, "");
    826                 spaces = -1;
    827             } else if (els) {
    828                 oldLength = string.length();
    829                 if (spaces < 0) {
    830                     spaces = 0;
    831                 }
    832                 string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
    833                 spaces -= string.length() - oldLength;
    834             }
    835             spaces += spaces_current;
    836 
    837             first = !first;
    838 
    839             if (oneline) {
    840                 continue;
    841             }
    842 
    843             size_t gone_szs = 0;
    844             size_t gone_els = 0;
    845 
    846             for(; pt != up->end(); ++pt) {
    847                 pp = *pt;
    848                 p = pp->getPid();
    849 
    850                 // If a PID no longer has any current logs, and is not
    851                 // active anymore, skip & report totals for gone.
    852                 elsTotal = pp->elementsTotal();
    853                 size_t szsTotal = pp->sizesTotal();
    854                 if (p == pp->gone) {
    855                     gone_szs += szsTotal;
    856                     gone_els += elsTotal;
    857                     continue;
    858                 }
    859                 els = pp->elements();
    860                 bool gone = pp->pidGone();
    861                 if (gone && (els == 0)) {
    862                     // ToDo: garbage collection: move this statistical bucket
    863                     //       from its current UID/PID to UID/? (races and
    864                     //       wrap around are our achilles heel). Below is
    865                     //       merely lipservice to catch PIDs that were still
    866                     //       around when the stats were pruned to zero.
    867                     gone_szs += szsTotal;
    868                     gone_els += elsTotal;
    869                     continue;
    870                 }
    871 
    872                 if (!first && (spaces > 0)) {
    873                     string.appendFormat("%*s", spaces, "");
    874                 }
    875                 spaces = 0;
    876 
    877                 intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
    878                 string.appendFormat(first ? "\n%-12s" : "%-12s",
    879                                     intermediate.string());
    880                 intermediate.clear();
    881 
    882                 oldLength = string.length();
    883                 string.appendFormat("%zu/%zu", szsTotal, elsTotal);
    884                 spaces += spaces_total + oldLength - string.length();
    885 
    886                 if (els == elsTotal) {
    887                     if (spaces < 0) {
    888                         spaces = 0;
    889                     }
    890                     string.appendFormat("%*s=", spaces, "");
    891                     spaces = -1;
    892                 } else if (els) {
    893                     oldLength = string.length();
    894                     if (spaces < 0) {
    895                         spaces = 0;
    896                     }
    897                     string.appendFormat("%*s%zu/%zu", spaces, "",
    898                                         pp->sizes(), els);
    899                     spaces -= string.length() - oldLength;
    900                 }
    901                 spaces += spaces_current;
    902 
    903                 first = !first;
    904             }
    905 
    906             if (gone_els) {
    907                 if (!first && (spaces > 0)) {
    908                     string.appendFormat("%*s", spaces, "");
    909                 }
    910 
    911                 intermediate = string.format("%d/?", u);
    912                 string.appendFormat(first ? "\n%-12s" : "%-12s",
    913                                     intermediate.string());
    914                 intermediate.clear();
    915 
    916                 spaces = spaces_total + spaces_current;
    917 
    918                 oldLength = string.length();
    919                 string.appendFormat("%zu/%zu", gone_szs, gone_els);
    920                 spaces -= string.length() - oldLength;
    921 
    922                 first = !first;
    923             }
    924         }
    925     }
    926 
    927     *buf = strdup(string.string());
    928 }
    929 
    930 uid_t LogStatistics::pidToUid(pid_t pid) {
    931     log_id_for_each(i) {
    932         LidStatistics &l = id(i);
    933         UidStatisticsCollection::iterator iu;
    934         for (iu = l.begin(); iu != l.end(); ++iu) {
    935             UidStatistics &u = *(*iu);
    936             PidStatisticsCollection::iterator ip;
    937             for (ip = u.begin(); ip != u.end(); ++ip) {
    938                 if ((*ip)->getPid() == pid) {
    939                     return u.getUid();
    940                 }
    941             }
    942         }
    943     }
    944     return getuid(); // associate this with the logger
    945 }
    946