logd: Statistics: Add up to 10 chattiest clients

- embellish pid name
- >1% of the logs
- fix PID gone detection (EPERM)
- some ? : cleanup

Change-Id: Iba3b306e1fee43e53931165819a398693910514b
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index fc6e6b2..5146030 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -63,7 +63,7 @@
 bool PidStatistics::subtract(unsigned short size) {
     mSizes -= size;
     --mElements;
-    return mElements == 0 && kill(pid, 0);
+    return (mElements == 0) && kill(pid, 0) && (errno != EPERM);
 }
 
 void PidStatistics::addTotal(size_t size, size_t element) {
@@ -508,6 +508,107 @@
         spaces += spaces_total;
     }
 
+    // Construct list of worst spammers by Pid
+    static const unsigned char num_spammers = 10;
+    bool header = false;
+
+    log_id_for_each(i) {
+        if (!(logMask & (1 << i))) {
+            continue;
+        }
+
+        PidStatisticsCollection pids;
+        pids.clear();
+
+        LidStatistics &l = id(i);
+        UidStatisticsCollection::iterator iu;
+        for (iu = l.begin(); iu != l.end(); ++iu) {
+            UidStatistics &u = *(*iu);
+            PidStatisticsCollection::iterator ip;
+            for (ip = u.begin(); ip != u.end(); ++ip) {
+                PidStatistics *p = (*ip);
+                if (p->getPid() == p->gone) {
+                    break;
+                }
+
+                size_t mySizes = p->sizes();
+
+                PidStatisticsCollection::iterator q;
+                unsigned char num = 0;
+                for (q = pids.begin(); q != pids.end(); ++q) {
+                    if (mySizes > (*q)->sizes()) {
+                        pids.insert(q, p);
+                        break;
+                    }
+                    // do we need to traverse deeper in the list?
+                    if (++num > num_spammers) {
+                        break;
+                    }
+                }
+                if (q == pids.end()) {
+                   pids.push_back(p);
+                }
+            }
+        }
+
+        size_t threshold = sizes(i);
+        if (threshold < 65536) {
+            threshold = 65536;
+        }
+        threshold /= 100;
+
+        PidStatisticsCollection::iterator pt = pids.begin();
+
+        for(int line = 0;
+                (pt != pids.end()) && (line < num_spammers);
+                ++line, pt = pids.erase(pt)) {
+            PidStatistics *p = *pt;
+
+            size_t sizes = p->sizes();
+            if (sizes < threshold) {
+                break;
+            }
+
+            char *name = p->getName();
+            pid_t pid = p->getPid();
+            if (!name || !*name) {
+                name = pidToName(pid);
+                if (name) {
+                    if (*name) {
+                        p->setName(name);
+                    } else {
+                        free(name);
+                        name = NULL;
+                    }
+                }
+            }
+
+            if (!header) {
+                string.appendFormat("\n\nChattiest clients:\n"
+                                    "log id %-*s PID[?] name",
+                                    spaces_total, "size/total");
+                header = true;
+            }
+
+            size_t sizesTotal = p->sizesTotal();
+
+            android::String8 sz("");
+            sz.appendFormat((sizes != sizesTotal) ? "%zu/%zu" : "%zu",
+                            sizes, sizesTotal);
+
+            android::String8 pd("");
+            pd.appendFormat("%u%c", pid,
+                            (kill(pid, 0) && (errno != EPERM)) ? '?' : ' ');
+
+            string.appendFormat("\n%-7s%-*s %-7s%s",
+                                line ? "" : android_log_id_to_name(i),
+                                spaces_total, sz.string(), pd.string(),
+                                name ? name : "");
+        }
+
+        pids.clear();
+    }
+
     if (dgram_qlen_statistics) {
         const unsigned short spaces_time = 6;
         const unsigned long long max_seconds = 100000;
@@ -562,7 +663,7 @@
             continue;
         }
 
-        bool header = false;
+        header = false;
         bool first = true;
 
         UidStatisticsCollection::iterator ut;
@@ -610,7 +711,7 @@
                                                  : "%d/%d")
                                              : "%d",
                                          u, p);
-            string.appendFormat((first) ? "\n%-12s" : "%-12s",
+            string.appendFormat(first ? "\n%-12s" : "%-12s",
                                 intermediate.string());
             intermediate.clear();
 
@@ -659,7 +760,7 @@
                     continue;
                 }
                 els = pp->elements();
-                bool gone = kill(p, 0);
+                bool gone = kill(p, 0) && (errno != EPERM);
                 if (gone && (els == 0)) {
                     // ToDo: garbage collection: move this statistical bucket
                     //       from its current UID/PID to UID/? (races and
@@ -676,8 +777,8 @@
                 }
                 spaces = 0;
 
-                intermediate = string.format((gone) ? "%d/%d?" : "%d/%d", u, p);
-                string.appendFormat((first) ? "\n%-12s" : "%-12s",
+                intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                     intermediate.string());
                 intermediate.clear();
 
@@ -711,7 +812,7 @@
                 }
 
                 intermediate = string.format("%d/?", u);
-                string.appendFormat((first) ? "\n%-12s" : "%-12s",
+                string.appendFormat(first ? "\n%-12s" : "%-12s",
                                     intermediate.string());
                 intermediate.clear();