• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <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 
PidStatistics(pid_t pid,char * name)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
PidStatistics(const PidStatistics & copy)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 
~PidStatistics()49 PidStatistics::~PidStatistics() {
50     free(name);
51 }
52 
pidGone()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 
setName(char * new_name)67 void PidStatistics::setName(char *new_name) {
68     free(name);
69     name = new_name;
70 }
71 
add(unsigned short size)72 void PidStatistics::add(unsigned short size) {
73     mSizesTotal += size;
74     ++mElementsTotal;
75     mSizes += size;
76     ++mElements;
77 }
78 
subtract(unsigned short size)79 bool PidStatistics::subtract(unsigned short size) {
80     mSizes -= size;
81     --mElements;
82     return (mElements == 0) && pidGone();
83 }
84 
addTotal(size_t size,size_t element)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
pidToName(pid_t pid)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 
UidStatistics(uid_t uid)114 UidStatistics::UidStatistics(uid_t uid)
115         : uid(uid)
116         , mSizes(0)
117         , mElements(0) {
118     Pids.clear();
119 }
120 
~UidStatistics()121 UidStatistics::~UidStatistics() {
122     PidStatisticsCollection::iterator it;
123     for (it = begin(); it != end();) {
124         delete (*it);
125         it = Pids.erase(it);
126     }
127 }
128 
add(unsigned short size,pid_t pid)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 
subtract(unsigned short size,pid_t pid)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 
sort()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 
sizes(pid_t pid)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 
elements(pid_t pid)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 
sizesTotal(pid_t pid)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 
elementsTotal(pid_t pid)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 
LidStatistics()263 LidStatistics::LidStatistics() {
264     Uids.clear();
265 }
266 
~LidStatistics()267 LidStatistics::~LidStatistics() {
268     UidStatisticsCollection::iterator it;
269     for (it = begin(); it != end();) {
270         delete (*it);
271         it = Uids.erase(it);
272     }
273 }
274 
add(unsigned short size,uid_t uid,pid_t pid)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 
subtract(unsigned short size,uid_t uid,pid_t pid)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 
sort()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 
sizes(uid_t uid,pid_t pid)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 
elements(uid_t uid,pid_t pid)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 
sizesTotal(uid_t uid,pid_t pid)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 
elementsTotal(uid_t uid,pid_t pid)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 
LogStatistics()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 
dgram_qlen(unsigned short bucket)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 
minimum(unsigned short bucket)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 
recordDiff(log_time diff,unsigned short bucket)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 
add(unsigned short size,log_id_t log_id,uid_t uid,pid_t pid)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 
subtract(unsigned short size,log_id_t log_id,uid_t uid,pid_t pid)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 
sizes(log_id_t log_id,uid_t uid,pid_t pid)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 
elements(log_id_t log_id,uid_t uid,pid_t pid)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 
sizesTotal(log_id_t log_id,uid_t uid,pid_t pid)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 
elementsTotal(log_id_t log_id,uid_t uid,pid_t pid)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 
format(char ** buf,uid_t uid,unsigned int logMask,log_time oldest)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 
pidToUid(pid_t pid)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