logd: class hierarcy for Uid and Pid statistics.

Add EntryBase and EntryBaseDropped base classes for statistical
entries to inherit from. Abstract add(), subtract() and drop()
methods to common LogBufferElement in each for entry policy decisions.
Some move of details out of LogStatistics.cpp and place them into
LogStatistics.h. Add statistical add(), subtract() and
drop() methods to hash table to call entries for policy.

Bug: 19608965
Change-Id: Ib8a33a8fe28871ef165d1632c6546a5c606231e8
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 7b6456d..6c08811 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -25,6 +25,9 @@
 #include <log/log.h>
 #include <log/log_read.h>
 
+// Hijack this header as a common include file used by most all sources
+// to report some utilities defined here and there.
+
 namespace android {
 
 // Furnished in main.cpp. Caller must own and free returned value
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index eadc4dd..10f7255 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -39,7 +39,7 @@
 namespace android {
 
 // caller must own and free character string
-static char *pidToName(pid_t pid) {
+char *pidToName(pid_t pid) {
     char *retval = NULL;
     if (pid == 0) { // special case from auditd for kernel
         retval = strdup("logd.auditd");
@@ -70,21 +70,7 @@
     mSizes[log_id] += size;
     ++mElements[log_id];
 
-    uid_t uid = e->getUid();
-    unsigned short dropped = e->getDropped();
-    android::hash_t hash = android::hash_type(uid);
-    uidTable_t &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index == -1) {
-        UidEntry initEntry(uid);
-        initEntry.add(size);
-        initEntry.add_dropped(dropped);
-        table.add(hash, initEntry);
-    } else {
-        UidEntry &entry = table.editEntryAt(index);
-        entry.add(size);
-        entry.add_dropped(dropped);
-    }
+    uidTable[log_id].add(e->getUid(), e);
 
     mSizesTotal[log_id] += size;
     ++mElementsTotal[log_id];
@@ -93,28 +79,7 @@
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        PidEntry initEntry(pid, uid, android::pidToName(pid));
-        initEntry.add(size);
-        initEntry.add_dropped(dropped);
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (entry.getUid() != uid) {
-            entry.setUid(uid);
-            entry.setName(android::pidToName(pid));
-        } else if (!entry.getName()) {
-            char *name = android::pidToName(pid);
-            if (name) {
-                entry.setName(name);
-            }
-        }
-        entry.add(size);
-        entry.add_dropped(dropped);
-    }
+    pidTable.add(e->getPid(), e);
 }
 
 void LogStatistics::subtract(LogBufferElement *e) {
@@ -123,31 +88,13 @@
     mSizes[log_id] -= size;
     --mElements[log_id];
 
-    uid_t uid = e->getUid();
-    unsigned short dropped = e->getDropped();
-    android::hash_t hash = android::hash_type(uid);
-    uidTable_t &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index != -1) {
-        UidEntry &entry = table.editEntryAt(index);
-        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
-            table.removeAt(index);
-        }
-    }
+    uidTable[log_id].subtract(e->getUid(), e);
 
     if (!enable) {
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index != -1) {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
-            pidTable.removeAt(index);
-        }
-    }
+    pidTable.subtract(e->getPid(), e);
 }
 
 // Atomically set an entry to drop
@@ -157,28 +104,13 @@
     unsigned short size = e->getMsgLen();
     mSizes[log_id] -= size;
 
-    uid_t uid = e->getUid();
-    android::hash_t hash = android::hash_type(uid);
-    typeof uidTable[0] &table = uidTable[log_id];
-    ssize_t index = table.find(-1, hash, uid);
-    if (index != -1) {
-        UidEntry &entry = table.editEntryAt(index);
-        entry.subtract(size);
-        entry.add_dropped(1);
-    }
+    uidTable[log_id].drop(e->getUid(), e);
 
     if (!enable) {
         return;
     }
 
-    pid_t pid = e->getPid();
-    hash = android::hash_type(pid);
-    index = pidTable.find(-1, hash, pid);
-    if (index != -1) {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        entry.subtract(size);
-        entry.add_dropped(1);
-    }
+    pidTable.drop(e->getPid(), e);
 }
 
 // caller must own and free character string
@@ -379,6 +311,7 @@
     }
 
     if (enable) {
+        // Pid table
         bool headerPrinted = false;
         std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
         ssize_t index = -1;
@@ -460,48 +393,14 @@
 }
 
 uid_t LogStatistics::pidToUid(pid_t pid) {
-    uid_t uid;
-    android::hash_t hash = android::hash_type(pid);
-    ssize_t index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        uid = android::pidToUid(pid);
-        PidEntry initEntry(pid, uid, android::pidToName(pid));
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        if (!entry.getName()) {
-            char *name = android::pidToName(pid);
-            if (name) {
-                entry.setName(name);
-            }
-        }
-        uid = entry.getUid();
-    }
-    return uid;
+    return pidTable.entryAt(pidTable.add(pid)).getUid();
 }
 
 // caller must free character string
 char *LogStatistics::pidToName(pid_t pid) {
-    char *name;
-
-    android::hash_t hash = android::hash_type(pid);
-    ssize_t index = pidTable.find(-1, hash, pid);
-    if (index == -1) {
-        name = android::pidToName(pid);
-        PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
-        pidTable.add(hash, initEntry);
-    } else {
-        PidEntry &entry = pidTable.editEntryAt(index);
-        const char *n = entry.getName();
-        if (n) {
-            name = strdup(n);
-        } else {
-            name = android::pidToName(pid);
-            if (name) {
-                entry.setName(strdup(name));
-            }
-        }
+    const char *name = pidTable.entryAt(pidTable.add(pid)).getName();
+    if (!name) {
+        return NULL;
     }
-
-    return name;
+    return strdup(name);
 }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f3110d7..a935c27 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -73,52 +73,139 @@
     ssize_t next(ssize_t index) {
         return android::BasicHashtable<TKey, TEntry>::next(index);
     }
+
+    size_t add(TKey key, LogBufferElement *e) {
+        android::hash_t hash = android::hash_type(key);
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+        if (index == -1) {
+            return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(e));
+        }
+        android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(e);
+        return index;
+    }
+
+    inline size_t add(TKey key) {
+        android::hash_t hash = android::hash_type(key);
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+        if (index == -1) {
+            return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(key));
+        }
+        android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(key);
+        return index;
+    }
+
+    void subtract(TKey key, LogBufferElement *e) {
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+        if ((index != -1)
+         && android::BasicHashtable<TKey, TEntry>::editEntryAt(index).subtract(e)) {
+            android::BasicHashtable<TKey, TEntry>::removeAt(index);
+        }
+    }
+
+    inline void drop(TKey key, LogBufferElement *e) {
+        ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+        if (index != -1) {
+            android::BasicHashtable<TKey, TEntry>::editEntryAt(index).drop(e);
+        }
+    }
+
 };
 
-struct UidEntry {
-    const uid_t uid;
+struct EntryBase {
     size_t size;
+
+    EntryBase():size(0) { }
+    EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+
+    size_t getSizes() const { return size; }
+
+    inline void add(LogBufferElement *e) { size += e->getMsgLen(); }
+    inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; }
+};
+
+struct EntryBaseDropped : public EntryBase {
     size_t dropped;
 
-    UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { }
+    EntryBaseDropped():dropped(0) { }
+    EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
 
-    inline const uid_t&getKey() const { return uid; }
-    size_t getSizes() const { return size; }
     size_t getDropped() const { return dropped; }
 
-    inline void add(size_t s) { size += s; }
-    inline void add_dropped(size_t d) { dropped += d; }
-    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
-    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+    inline void add(LogBufferElement *e) {
+        dropped += e->getDropped();
+        EntryBase::add(e);
+    }
+    inline bool subtract(LogBufferElement *e) {
+        dropped -= e->getDropped();
+        return EntryBase::subtract(e) && !dropped;
+    }
+    inline void drop(LogBufferElement *e) {
+        dropped += 1;
+        EntryBase::subtract(e);
+    }
 };
 
-struct PidEntry {
+struct UidEntry : public EntryBaseDropped {
+    const uid_t uid;
+
+    UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
+
+    inline const uid_t&getKey() const { return uid; }
+};
+
+namespace android {
+// caller must own and free character string
+char *pidToName(pid_t pid);
+uid_t pidToUid(pid_t pid);
+}
+
+struct PidEntry : public EntryBaseDropped {
     const pid_t pid;
     uid_t uid;
     char *name;
-    size_t size;
-    size_t dropped;
 
-    PidEntry(pid_t p, uid_t u, char *n):pid(p),uid(u),name(n),size(0),dropped(0) { }
+    PidEntry(pid_t p):
+        EntryBaseDropped(),
+        pid(p),
+        uid(android::pidToUid(p)),
+        name(android::pidToName(pid)) { }
+    PidEntry(LogBufferElement *e):
+        EntryBaseDropped(e),
+        pid(e->getPid()),
+        uid(e->getUid()),
+        name(android::pidToName(e->getPid())) { }
     PidEntry(const PidEntry &c):
+        EntryBaseDropped(c),
         pid(c.pid),
         uid(c.uid),
-        name(c.name ? strdup(c.name) : NULL),
-        size(c.size),
-        dropped(c.dropped) { }
+        name(c.name ? strdup(c.name) : NULL) { }
     ~PidEntry() { free(name); }
 
     const pid_t&getKey() const { return pid; }
     const uid_t&getUid() const { return uid; }
-    uid_t&setUid(uid_t u) { return uid = u; }
     const char*getName() const { return name; }
-    char *setName(char *n) { free(name); return name = n; }
-    size_t getSizes() const { return size; }
-    size_t getDropped() const { return dropped; }
-    inline void add(size_t s) { size += s; }
-    inline void add_dropped(size_t d) { dropped += d; }
-    inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
-    inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+
+    inline void add(pid_t p) {
+        if (!name) {
+            char *n = android::pidToName(p);
+            if (n) {
+                name = n;
+            }
+        }
+    }
+
+    inline void add(LogBufferElement *e) {
+        uid_t u = e->getUid();
+        if (getUid() != u) {
+            uid = u;
+            free(name);
+            name = android::pidToName(e->getPid());
+        } else {
+            add(e->getPid());
+        }
+        EntryBaseDropped::add(e);
+    }
+
 };
 
 // Log Statistics