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 ©)
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 || (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
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
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.
pidToName(pid_t pid)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
UidStatistics(uid_t uid)119 UidStatistics::UidStatistics(uid_t uid)
120 : uid(uid)
121 , mSizes(0)
122 , mElements(0) {
123 Pids.clear();
124 }
125
~UidStatistics()126 UidStatistics::~UidStatistics() {
127 PidStatisticsCollection::iterator it;
128 for (it = begin(); it != end();) {
129 delete (*it);
130 it = erase(it);
131 }
132 }
133
add(unsigned short size,pid_t pid)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
subtract(unsigned short size,pid_t pid)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
sort()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
sizes(pid_t pid)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
elements(pid_t pid)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
sizesTotal(pid_t pid)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
elementsTotal(pid_t pid)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
LidStatistics()268 LidStatistics::LidStatistics() {
269 Uids.clear();
270 }
271
~LidStatistics()272 LidStatistics::~LidStatistics() {
273 UidStatisticsCollection::iterator it;
274 for (it = begin(); it != end();) {
275 delete (*it);
276 it = Uids.erase(it);
277 }
278 }
279
add(unsigned short size,uid_t uid,pid_t pid)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
subtract(unsigned short size,uid_t uid,pid_t pid)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
sort()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
sizes(uid_t uid,pid_t pid)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
elements(uid_t uid,pid_t pid)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
sizesTotal(uid_t uid,pid_t pid)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
elementsTotal(uid_t uid,pid_t pid)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
LogStatistics()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
dgramQlen(unsigned short bucket)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
minimum(unsigned short bucket)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
recordDiff(log_time diff,unsigned short bucket)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
add(unsigned short size,log_id_t log_id,uid_t uid,pid_t pid)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
subtract(unsigned short size,log_id_t log_id,uid_t uid,pid_t pid)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
sizes(log_id_t log_id,uid_t uid,pid_t pid)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
elements(log_id_t log_id,uid_t uid,pid_t pid)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
sizesTotal(log_id_t log_id,uid_t uid,pid_t pid)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
elementsTotal(log_id_t log_id,uid_t uid,pid_t pid)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
format(char ** buf,uid_t uid,unsigned int logMask,log_time oldest)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
pidToUid(pid_t pid)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