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