logd: Add Tag statistics

- Optional class of statistics for events Tags
- export tagToName from LogBuffer (located in main.cp to address
  https://android-review.googlesource.com/#/c/110204)
- Can not handle dropped because getTag() can not work,
  will need to be fixed if we start filtering.

Bug: 19608965
Change-Id: I7b90607ca588bf37bab71f19b1570a290e772776
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 2eab4dd..4511e0b 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -80,6 +80,11 @@
     }
 
     pidTable.add(e->getPid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.add(tag, e);
+    }
 }
 
 void LogStatistics::subtract(LogBufferElement *e) {
@@ -95,6 +100,11 @@
     }
 
     pidTable.subtract(e->getPid(), e);
+
+    uint32_t tag = e->getTag();
+    if (tag) {
+        tagTable.subtract(tag, e);
+    }
 }
 
 // Atomically set an entry to drop
@@ -373,6 +383,51 @@
         }
     }
 
+    if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+        // Tag table
+        bool headerPrinted = false;
+        std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+        ssize_t index = -1;
+        while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+            const TagEntry *entry = sorted[index];
+            uid_t u = entry->getUid();
+            if ((uid != AID_ROOT) && (u != uid)) {
+                continue;
+            }
+
+            android::String8 pruned("");
+
+            if (!headerPrinted) {
+                output.appendFormat("\n\n");
+                android::String8 name("Chattiest events log buffer TAGs:");
+                android::String8 size("Size");
+                format_line(output, name, size, pruned);
+
+                name.setTo("    TAG/UID   TAGNAME");
+                size.setTo("BYTES");
+                format_line(output, name, size, pruned);
+
+                headerPrinted = true;
+            }
+
+            android::String8 name("");
+            if (u == (uid_t)-1) {
+                name.appendFormat("%7u", entry->getKey());
+            } else {
+                name.appendFormat("%7u/%u", entry->getKey(), u);
+            }
+            const char *n = entry->getName();
+            if (n) {
+                name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+            }
+
+            android::String8 size("");
+            size.appendFormat("%zu", entry->getSizes());
+
+            format_line(output, name, size, pruned);
+        }
+    }
+
     *buf = strdup(output.string());
 }