Merge "Implement the ssh(1) escaping rules."
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
index 3e823e9..f78daeb 100644
--- a/adb/test_track_devices.cpp
+++ b/adb/test_track_devices.cpp
@@ -62,7 +62,7 @@
         if (!android::base::ReadFully(s, buffer, len))
             panic("could not read data");
 
-        printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
+        printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
     }
     close(s);
 }
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
index 230adb8..84ec538 100644
--- a/base/include/base/logging.h
+++ b/base/include/base/logging.h
@@ -17,6 +17,15 @@
 #ifndef BASE_LOGGING_H
 #define BASE_LOGGING_H
 
+#ifdef ERROR
+#error ERROR is already defined. If this is Windows code, #define NOGDI before \
+including anything.
+#endif
+
+#ifdef _WIN32
+#define NOGDI // Suppress the evil ERROR macro.
+#endif
+
 #include <functional>
 #include <memory>
 #include <ostream>
diff --git a/base/logging.cpp b/base/logging.cpp
index 83957b3..7a08c39 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -35,7 +35,6 @@
 #ifndef _WIN32
 #include <mutex>
 #else
-#define NOGDI // Suppress the evil ERROR macro.
 #include <windows.h>
 #endif
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 059c031..b6c6196 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 b063630..10f7255 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -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