Merge "system/core: fix iterator for LruCache"
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 808d17a..2f7cbfb 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -183,7 +183,7 @@
     static const char comm_str[] = " comm=\"";
     const char *comm = strstr(str, comm_str);
     const char *estr = str + strlen(str);
-    char *commfree = NULL;
+    const char *commfree = NULL;
     if (comm) {
         estr = comm;
         comm += sizeof(comm_str) - 1;
@@ -231,7 +231,7 @@
         // end scope for main buffer
     }
 
-    free(commfree);
+    free(const_cast<char *>(commfree));
     free(str);
 
     if (notify) {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index d8e0b90..371c796 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -78,9 +78,9 @@
     std::string formatPrune() { return mPrune.format(); }
 
     // helper must be protected directly or implicitly by lock()/unlock()
-    char *pidToName(pid_t pid) { return stats.pidToName(pid); }
+    const char *pidToName(pid_t pid) { return stats.pidToName(pid); }
     uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
-    char *uidToName(uid_t uid) { return stats.uidToName(uid); }
+    const char *uidToName(uid_t uid) { return stats.uidToName(uid); }
     void lock() { pthread_mutex_lock(&mLogElementsLock); }
     void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
 
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 150ce22..c4c302b 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -113,9 +113,9 @@
 
     static const char format_uid[] = "uid=%u%s%s expire %u line%s";
     parent->lock();
-    char *name = parent->uidToName(mUid);
+    const char *name = parent->uidToName(mUid);
     parent->unlock();
-    char *commName = android::tidToName(mTid);
+    const char *commName = android::tidToName(mTid);
     if (!commName && (mTid != mPid)) {
         commName = android::tidToName(mPid);
     }
@@ -128,28 +128,28 @@
         size_t len = strlen(name + 1);
         if (!strncmp(name + 1, commName + 1, len)) {
             if (commName[len + 1] == '\0') {
-                free(commName);
+                free(const_cast<char *>(commName));
                 commName = NULL;
             } else {
-                free(name);
+                free(const_cast<char *>(name));
                 name = NULL;
             }
         }
     }
     if (name) {
-        char *p = NULL;
-        asprintf(&p, "(%s)", name);
-        if (p) {
-            free(name);
-            name = p;
+        char *buf = NULL;
+        asprintf(&buf, "(%s)", name);
+        if (buf) {
+            free(const_cast<char *>(name));
+            name = buf;
         }
     }
     if (commName) {
-        char *p = NULL;
-        asprintf(&p, " %s", commName);
-        if (p) {
-            free(commName);
-            commName = p;
+        char *buf = NULL;
+        asprintf(&buf, " %s", commName);
+        if (buf) {
+            free(const_cast<char *>(commName));
+            commName = buf;
         }
     }
     // identical to below to calculate the buffer size required
@@ -166,18 +166,19 @@
 
     buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
     if (!buffer) {
-        free(name);
-        free(commName);
+        free(const_cast<char *>(name));
+        free(const_cast<char *>(commName));
         return 0;
     }
 
     size_t retval = hdrLen + len;
     if (mLogId == LOG_ID_EVENTS) {
-        android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
+        android_log_event_string_t *event =
+            reinterpret_cast<android_log_event_string_t *>(buffer);
 
-        e->header.tag = htole32(LOGD_LOG_TAG);
-        e->type = EVENT_TYPE_STRING;
-        e->length = htole32(len);
+        event->header.tag = htole32(LOGD_LOG_TAG);
+        event->type = EVENT_TYPE_STRING;
+        event->length = htole32(len);
     } else {
         ++retval;
         buffer[0] = ANDROID_LOG_INFO;
@@ -187,8 +188,8 @@
     snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
              commName ? commName : "",
              mDropped, (mDropped > 1) ? "s" : "");
-    free(name);
-    free(commName);
+    free(const_cast<char *>(name));
+    free(const_cast<char *>(commName));
 
     return retval;
 }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index a9c3086..c3b10ad 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,15 +14,12 @@
  * limitations under the License.
  */
 
-#include <algorithm> // std::max
 #include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <base/stringprintf.h>
 #include <log/logger.h>
-#include <private/android_filesystem_config.h>
 
 #include "LogStatistics.h"
 
@@ -63,9 +60,9 @@
 
 }
 
-void LogStatistics::add(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::add(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] += size;
     ++mElements[log_id];
 
@@ -76,24 +73,24 @@
         return;
     }
 
-    uidTable[log_id].add(e->getUid(), e);
+    uidTable[log_id].add(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.add(e->getPid(), e);
-    tidTable.add(e->getTid(), e);
+    pidTable.add(element->getPid(), element);
+    tidTable.add(element->getTid(), element);
 
-    uint32_t tag = e->getTag();
+    uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.add(tag, e);
+        tagTable.add(tag, element);
     }
 }
 
-void LogStatistics::subtract(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::subtract(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] -= size;
     --mElements[log_id];
 
@@ -101,40 +98,40 @@
         return;
     }
 
-    uidTable[log_id].subtract(e->getUid(), e);
+    uidTable[log_id].subtract(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.subtract(e->getPid(), e);
-    tidTable.subtract(e->getTid(), e);
+    pidTable.subtract(element->getPid(), element);
+    tidTable.subtract(element->getTid(), element);
 
-    uint32_t tag = e->getTag();
+    uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.subtract(tag, e);
+        tagTable.subtract(tag, element);
     }
 }
 
 // Atomically set an entry to drop
 // entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::drop(LogBufferElement *e) {
-    log_id_t log_id = e->getLogId();
-    unsigned short size = e->getMsgLen();
+void LogStatistics::drop(LogBufferElement *element) {
+    log_id_t log_id = element->getLogId();
+    unsigned short size = element->getMsgLen();
     mSizes[log_id] -= size;
 
-    uidTable[log_id].drop(e->getUid(), e);
+    uidTable[log_id].drop(element->getUid(), element);
 
     if (!enable) {
         return;
     }
 
-    pidTable.drop(e->getPid(), e);
-    tidTable.drop(e->getTid(), e);
+    pidTable.drop(element->getPid(), element);
+    tidTable.drop(element->getTid(), element);
 }
 
 // caller must own and free character string
-char *LogStatistics::uidToName(uid_t uid) {
+const char *LogStatistics::uidToName(uid_t uid) const {
     // Local hard coded favourites
     if (uid == AID_LOGD) {
         return strdup("auditd");
@@ -152,7 +149,7 @@
 
     // Parse /data/system/packages.list
     uid_t userId = uid % AID_USER;
-    char *name = android::uidToName(userId);
+    const char *name = android::uidToName(userId);
     if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
         name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
     }
@@ -161,17 +158,17 @@
     }
 
     // report uid -> pid(s) -> pidToName if unique
-    for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
+    for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
         const PidEntry &entry = it->second;
 
         if (entry.getUid() == uid) {
-            const char *n = entry.getName();
+            const char *nameTmp = entry.getName();
 
-            if (n) {
+            if (nameTmp) {
                 if (!name) {
-                    name = strdup(n);
-                } else if (fast<strcmp>(name, n)) {
-                    free(name);
+                    name = strdup(nameTmp);
+                } else if (fast<strcmp>(name, nameTmp)) {
+                    free(const_cast<char *>(name));
                     name = NULL;
                     break;
                 }
@@ -183,28 +180,152 @@
     return name;
 }
 
-static std::string format_line(
-        const std::string &name,
-        const std::string &size,
-        const std::string &pruned) {
-    static const size_t pruned_len = 6;
-    static const size_t total_len = 70 + pruned_len;
-
-    ssize_t drop_len = std::max(pruned.length() + 1, pruned_len);
-    ssize_t size_len = std::max(size.length() + 1,
-                                total_len - name.length() - drop_len - 1);
-
-    if (pruned.length()) {
-        return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
-                                           (int)size_len, size.c_str(),
-                                           (int)drop_len, pruned.c_str());
-    } else {
-        return android::base::StringPrintf("%s%*s\n", name.c_str(),
-                                           (int)size_len, size.c_str());
-    }
+std::string UidEntry::formatHeader(const std::string &name, log_id_t id) const {
+    bool isprune = worstUidEnabledForLogid(id);
+    return formatLine(android::base::StringPrintf(
+                          name.c_str(), android_log_id_to_name(id)),
+                      std::string("Size"),
+                      std::string(isprune ? "Pruned" : ""))
+         + formatLine(std::string("UID   PACKAGE"),
+                      std::string("BYTES"),
+                      std::string(isprune ? "NUM" : ""));
 }
 
-std::string LogStatistics::format(uid_t uid, unsigned int logMask) {
+std::string UidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+    uid_t uid = getKey();
+    std::string name = android::base::StringPrintf("%u", uid);
+    const char *nameTmp = stat.uidToName(uid);
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+    }
+
+    std::string size = android::base::StringPrintf("%zu", getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string("Pruned"))
+         + formatLine(std::string("  PID/UID   COMMAND LINE"),
+                      std::string("BYTES"),
+                      std::string("NUM"));
+}
+
+std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+    uid_t uid = getUid();
+    std::string name = android::base::StringPrintf("%5u/%u",
+                                                   getKey(), uid);
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+    } else if ((nameTmp = stat.uidToName(uid))) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const {
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string("Pruned"))
+         + formatLine(std::string("  TID/UID   COMM"),
+                      std::string("BYTES"),
+                      std::string("NUM"));
+}
+
+std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const {
+    uid_t uid = getUid();
+    std::string name = android::base::StringPrintf("%5u/%u",
+                                                   getKey(), uid);
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+    } else if ((nameTmp = stat.uidToName(uid))) {
+        // if we do not have a PID name, lets punt to try UID name?
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+            "", nameTmp);
+        free(const_cast<char *>(nameTmp));
+        // We tried, better to not have a name at all, we still
+        // have TID/UID by number to report in any case.
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+    size_t dropped = getDropped();
+    if (dropped) {
+        pruned = android::base::StringPrintf("%zu", dropped);
+    }
+
+    return formatLine(name, size, pruned);
+}
+
+std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const {
+    bool isprune = worstUidEnabledForLogid(id);
+    return formatLine(name,
+                      std::string("Size"),
+                      std::string(isprune ? "Prune" : ""))
+         + formatLine(std::string("    TAG/UID   TAGNAME"),
+                      std::string("BYTES"),
+                      std::string(isprune ? "NUM" : ""));
+}
+
+std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const {
+    std::string name;
+    uid_t uid = getUid();
+    if (uid == (uid_t)-1) {
+        name = android::base::StringPrintf("%7u",
+                                           getKey());
+    } else {
+        name = android::base::StringPrintf("%7u/%u",
+                                           getKey(), uid);
+    }
+    const char *nameTmp = getName();
+    if (nameTmp) {
+        name += android::base::StringPrintf(
+            "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
+            "", nameTmp);
+    }
+
+    std::string size = android::base::StringPrintf("%zu",
+                                                   getSizes());
+
+    std::string pruned = "";
+
+    return formatLine(name, size, pruned);
+}
+
+std::string LogStatistics::format(uid_t uid, unsigned int logMask) const {
     static const unsigned short spaces_total = 19;
 
     // Report on total logging, current and for all time
@@ -227,7 +348,7 @@
     }
 
     spaces = 4;
-    output += android::base::StringPrintf("\nTotal");
+    output += "\nTotal";
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -244,7 +365,7 @@
     }
 
     spaces = 6;
-    output += android::base::StringPrintf("\nNow");
+    output += "\nNow";
 
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
@@ -266,245 +387,30 @@
 
     // Report on Chattiest
 
+    std::string name;
+
     // Chattiest by application (UID)
-    static const size_t maximum_sorted_entries = 32;
     log_id_for_each(id) {
         if (!(logMask & (1 << id))) {
             continue;
         }
 
-        bool headerPrinted = false;
-        std::unique_ptr<const UidEntry *[]> sorted = sort(maximum_sorted_entries, id);
-        ssize_t index = -1;
-        while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const UidEntry *entry = sorted[index];
-            uid_t u = entry->getKey();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name;
-                if (uid == AID_ROOT) {
-                    name = android::base::StringPrintf(
-                        "Chattiest UIDs in %s log buffer:",
-                        android_log_id_to_name(id));
-                } else {
-                    name = android::base::StringPrintf(
-                        "Logging for your UID in %s log buffer:",
-                        android_log_id_to_name(id));
-                }
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                if (!worstUidEnabledForLogid(id)) {
-                    pruned = "";
-                }
-                output += format_line(name, size, pruned);
-
-                name = "UID   PACKAGE";
-                size = "BYTES";
-                pruned = "LINES";
-                if (!worstUidEnabledForLogid(id)) {
-                    pruned = "";
-                }
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%u", u);
-            char *n = uidToName(u);
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
-                    "", n);
-                free(n);
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
+        name = (uid == AID_ROOT)
+            ? "Chattiest UIDs in %s log buffer:"
+            : "Logging for your UID in %s log buffer:";
+        output += uidTable[id].format(*this, uid, name, id);
     }
 
     if (enable) {
-        // Pid table
-        bool headerPrinted = false;
-        std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
-        ssize_t index = -1;
-        while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const PidEntry *entry = sorted[index];
-            uid_t u = entry->getUid();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name;
-                if (uid == AID_ROOT) {
-                    name = android::base::StringPrintf("Chattiest PIDs:");
-                } else {
-                    name = android::base::StringPrintf("Logging for this PID:");
-                }
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                output += format_line(name, size, pruned);
-
-                name = "  PID/UID   COMMAND LINE";
-                size = "BYTES";
-                pruned = "LINES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%5u/%u",
-                                                           entry->getKey(), u);
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                    "", n);
-            } else {
-                char *un = uidToName(u);
-                if (un) {
-                    name += android::base::StringPrintf(
-                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                        "", un);
-                    free(un);
-                }
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
-    }
-
-    if (enable) {
-        // Tid table
-        bool headerPrinted = false;
-        // sort() returns list of references, unique_ptr makes sure self-delete
-        std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
-        ssize_t index = -1;
-        while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
-            const TidEntry *entry = sorted[index];
-            uid_t u = entry->getUid();
-            if ((uid != AID_ROOT) && (u != uid)) {
-                continue;
-            }
-
-            if (!headerPrinted) { // Only print header if we have table to print
-                output += android::base::StringPrintf("\n\n");
-                std::string name = "Chattiest TIDs:";
-                std::string size = "Size";
-                std::string pruned = "Pruned";
-                output += format_line(name, size, pruned);
-
-                name = "  TID/UID   COMM";
-                size = "BYTES";
-                pruned = "LINES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name = android::base::StringPrintf("%5u/%u",
-                                                           entry->getKey(), u);
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                    "", n);
-            } else {
-                // if we do not have a PID name, lets punt to try UID name?
-                char *un = uidToName(u);
-                if (un) {
-                    name += android::base::StringPrintf(
-                        "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
-                        "", un);
-                    free(un);
-                }
-                // We tried, better to not have a name at all, we still
-                // have TID/UID by number to report in any case.
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            std::string pruned = "";
-            size_t dropped = entry->getDropped();
-            if (dropped) {
-                pruned = android::base::StringPrintf("%zu", dropped);
-            }
-
-            output += format_line(name, size, pruned);
-        }
+        name = (uid == AID_ROOT) ? "Chattiest PIDs:" : "Logging for this PID:";
+        output += pidTable.format(*this, uid, name);
+        name = "Chattiest TIDs:";
+        output += tidTable.format(*this, uid, name);
     }
 
     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;
-            }
-
-            std::string pruned = "";
-
-            if (!headerPrinted) {
-                output += android::base::StringPrintf("\n\n");
-                std::string name = "Chattiest events log buffer TAGs:";
-                std::string size = "Size";
-                output += format_line(name, size, pruned);
-
-                name = "    TAG/UID   TAGNAME";
-                size = "BYTES";
-                output += format_line(name, size, pruned);
-
-                headerPrinted = true;
-            }
-
-            std::string name;
-            if (u == (uid_t)-1) {
-                name = android::base::StringPrintf("%7u",
-                                                   entry->getKey());
-            } else {
-                name = android::base::StringPrintf("%7u/%u",
-                                                   entry->getKey(), u);
-            }
-            const char *n = entry->getName();
-            if (n) {
-                name += android::base::StringPrintf(
-                    "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
-                    "", n);
-            }
-
-            std::string size = android::base::StringPrintf("%zu",
-                                                           entry->getSizes());
-
-            output += format_line(name, size, pruned);
-        }
+        name = "Chattiest events log buffer TAGs:";
+        output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
     }
 
     return output;
@@ -536,8 +442,10 @@
 }
 
 // caller must free character string
-char *LogStatistics::pidToName(pid_t pid) {
-    const char *name = pidTable.add(pid)->second.getName();
+const char *LogStatistics::pidToName(pid_t pid) const {
+    // An inconvenient truth ... getName() can alter the object
+    pidTable_t &writablePidTable = const_cast<pidTable_t &>(pidTable);
+    const char *name = writablePidTable.add(pid)->second.getName();
     if (!name) {
         return NULL;
     }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 5a44d59..dd13380 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -21,9 +21,13 @@
 #include <stdlib.h>
 #include <sys/types.h>
 
+#include <algorithm> // std::max
+#include <string>    // std::string
 #include <unordered_map>
 
+#include <base/stringprintf.h>
 #include <log/log.h>
+#include <private/android_filesystem_config.h>
 
 #include "LogBufferElement.h"
 #include "LogUtils.h"
@@ -31,6 +35,8 @@
 #define log_id_for_each(i) \
     for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
 
+class LogStatistics;
+
 template <typename TKey, typename TEntry>
 class LogHashtable {
 
@@ -39,50 +45,43 @@
 public:
 
     typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
+    typedef typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
-    std::unique_ptr<const TEntry *[]> sort(size_t n) {
-        if (!n) {
+    std::unique_ptr<const TEntry *[]> sort(size_t len) const {
+        if (!len) {
             std::unique_ptr<const TEntry *[]> sorted(NULL);
             return sorted;
         }
 
-        const TEntry **retval = new const TEntry* [n];
-        memset(retval, 0, sizeof(*retval) * n);
+        const TEntry **retval = new const TEntry* [len];
+        memset(retval, 0, sizeof(*retval) * len);
 
-        for(iterator it = map.begin(); it != map.end(); ++it) {
+        for(const_iterator it = map.begin(); it != map.end(); ++it) {
             const TEntry &entry = it->second;
-            size_t s = entry.getSizes();
-            ssize_t i = n - 1;
-            while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0))
+            size_t sizes = entry.getSizes();
+            ssize_t index = len - 1;
+            while ((!retval[index] || (sizes > retval[index]->getSizes()))
+                    && (--index >= 0))
                 ;
-            if (++i < (ssize_t)n) {
-                size_t b = n - i - 1;
-                if (b) {
-                    memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
+            if (++index < (ssize_t)len) {
+                size_t num = len - index - 1;
+                if (num) {
+                    memmove(&retval[index + 1], &retval[index],
+                            num * sizeof(retval[0]));
                 }
-                retval[i] = &entry;
+                retval[index] = &entry;
             }
         }
         std::unique_ptr<const TEntry *[]> sorted(retval);
         return sorted;
     }
 
-    // Iteration handler for the sort method output
-    static ssize_t next(ssize_t index, std::unique_ptr<const TEntry *[]> &sorted, size_t n) {
-        ++index;
-        if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index]
-         || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) {
-            return -1;
-        }
-        return index;
-    }
-
-    inline iterator add(TKey key, LogBufferElement *e) {
+    inline iterator add(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
         if (it == map.end()) {
-            it = map.insert(std::make_pair(key, TEntry(e))).first;
+            it = map.insert(std::make_pair(key, TEntry(element))).first;
         } else {
-            it->second.add(e);
+            it->second.add(element);
         }
         return it;
     }
@@ -97,65 +96,138 @@
         return it;
     }
 
-    void subtract(TKey key, LogBufferElement *e) {
+    void subtract(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
-        if ((it != map.end()) && it->second.subtract(e)) {
+        if ((it != map.end()) && it->second.subtract(element)) {
             map.erase(it);
         }
     }
 
-    inline void drop(TKey key, LogBufferElement *e) {
+    inline void drop(TKey key, LogBufferElement *element) {
         iterator it = map.find(key);
         if (it != map.end()) {
-            it->second.drop(e);
+            it->second.drop(element);
         }
     }
 
     inline iterator begin() { return map.begin(); }
+    inline const_iterator begin() const { return map.begin(); }
     inline iterator end() { return map.end(); }
+    inline const_iterator end() const { return map.end(); }
 
+    std::string format(
+            const LogStatistics &stat,
+            uid_t uid,
+            const std::string &name = std::string(""),
+            log_id_t id = LOG_ID_MAX) const {
+        static const size_t maximum_sorted_entries = 32;
+        std::string output;
+        std::unique_ptr<const TEntry *[]> sorted = sort(maximum_sorted_entries);
+
+        if (!sorted.get()) {
+            return output;
+        }
+        bool headerPrinted = false;
+        for (size_t index = 0; index < maximum_sorted_entries; ++index) {
+            const TEntry *entry = sorted[index];
+            if (!entry) {
+                break;
+            }
+            if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
+                break;
+            }
+            if ((uid != AID_ROOT) && (uid != entry->getUid())) {
+                continue;
+            }
+            if (!headerPrinted) {
+                output += "\n\n";
+                output += entry->formatHeader(name, id);
+                headerPrinted = true;
+            }
+            output += entry->format(stat, id);
+        }
+        return output;
+    }
 };
 
+namespace EntryBaseConstants {
+    static constexpr size_t pruned_len = 14;
+    static constexpr size_t total_len = 80;
+}
+
 struct EntryBase {
     size_t size;
 
     EntryBase():size(0) { }
-    EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+    EntryBase(LogBufferElement *element):size(element->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; }
+    inline void add(LogBufferElement *element) { size += element->getMsgLen(); }
+    inline bool subtract(LogBufferElement *element) {
+        size -= element->getMsgLen();
+        return !size;
+    }
+
+    static std::string formatLine(
+            const std::string &name,
+            const std::string &size,
+            const std::string &pruned) {
+        ssize_t drop_len = std::max(pruned.length() + 1,
+                                    EntryBaseConstants::pruned_len);
+        ssize_t size_len = std::max(size.length() + 1,
+                                    EntryBaseConstants::total_len
+                                        - name.length() - drop_len - 1);
+
+        if (pruned.length()) {
+            return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
+                                               (int)size_len, size.c_str(),
+                                               (int)drop_len, pruned.c_str());
+        } else {
+            return android::base::StringPrintf("%s%*s\n", name.c_str(),
+                                               (int)size_len, size.c_str());
+        }
+    }
 };
 
 struct EntryBaseDropped : public EntryBase {
     size_t dropped;
 
     EntryBaseDropped():dropped(0) { }
-    EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
+    EntryBaseDropped(LogBufferElement *element):
+            EntryBase(element),
+            dropped(element->getDropped()){
+    }
 
     size_t getDropped() const { return dropped; }
 
-    inline void add(LogBufferElement *e) {
-        dropped += e->getDropped();
-        EntryBase::add(e);
+    inline void add(LogBufferElement *element) {
+        dropped += element->getDropped();
+        EntryBase::add(element);
     }
-    inline bool subtract(LogBufferElement *e) {
-        dropped -= e->getDropped();
-        return EntryBase::subtract(e) && !dropped;
+    inline bool subtract(LogBufferElement *element) {
+        dropped -= element->getDropped();
+        return EntryBase::subtract(element) && !dropped;
     }
-    inline void drop(LogBufferElement *e) {
+    inline void drop(LogBufferElement *element) {
         dropped += 1;
-        EntryBase::subtract(e);
+        EntryBase::subtract(element);
     }
 };
 
 struct UidEntry : public EntryBaseDropped {
     const uid_t uid;
 
-    UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
+    UidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            uid(element->getUid()) {
+    }
 
     inline const uid_t&getKey() const { return uid; }
+    inline const uid_t&getUid() const { return uid; }
+
+    std::string formatHeader(const std::string &name, log_id_t id) const;
+    std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
 namespace android {
@@ -167,51 +239,54 @@
     uid_t uid;
     char *name;
 
-    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) { }
+    PidEntry(pid_t pid):
+            EntryBaseDropped(),
+            pid(pid),
+            uid(android::pidToUid(pid)),
+            name(android::pidToName(pid)) {
+    }
+    PidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            pid(element->getPid()),
+            uid(element->getUid()),
+            name(android::pidToName(pid)) {
+    }
+    PidEntry(const PidEntry &element):
+            EntryBaseDropped(element),
+            pid(element.pid),
+            uid(element.uid),
+            name(element.name ? strdup(element.name) : NULL) {
+    }
     ~PidEntry() { free(name); }
 
     const pid_t&getKey() const { return pid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
-    inline void add(pid_t p) {
+    inline void add(pid_t newPid) {
         if (name && !fast<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
         if (!name) {
-            char *n = android::pidToName(p);
-            if (n) {
-                name = n;
-            }
+            name = android::pidToName(newPid);
         }
     }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (getUid() != u) {
-            uid = u;
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (getUid() != incomingUid) {
+            uid = incomingUid;
             free(name);
-            name = android::pidToName(e->getPid());
+            name = android::pidToName(element->getPid());
         } else {
-            add(e->getPid());
+            add(element->getPid());
         }
-        EntryBaseDropped::add(e);
+        EntryBaseDropped::add(element);
     }
+
+    std::string formatHeader(const std::string &name, log_id_t id) const;
+    std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
 struct TidEntry : public EntryBaseDropped {
@@ -219,73 +294,80 @@
     uid_t uid;
     char *name;
 
-    TidEntry(pid_t t):
-        EntryBaseDropped(),
-        tid(t),
-        uid(android::pidToUid(t)),
-        name(android::tidToName(tid)) { }
-    TidEntry(LogBufferElement *e):
-        EntryBaseDropped(e),
-        tid(e->getTid()),
-        uid(e->getUid()),
-        name(android::tidToName(e->getTid())) { }
-    TidEntry(const TidEntry &c):
-        EntryBaseDropped(c),
-        tid(c.tid),
-        uid(c.uid),
-        name(c.name ? strdup(c.name) : NULL) { }
+    TidEntry(pid_t tid):
+            EntryBaseDropped(),
+            tid(tid),
+            uid(android::pidToUid(tid)),
+            name(android::tidToName(tid)) {
+    }
+    TidEntry(LogBufferElement *element):
+            EntryBaseDropped(element),
+            tid(element->getTid()),
+            uid(element->getUid()),
+            name(android::tidToName(tid)) {
+    }
+    TidEntry(const TidEntry &element):
+            EntryBaseDropped(element),
+            tid(element.tid),
+            uid(element.uid),
+            name(element.name ? strdup(element.name) : NULL) {
+    }
     ~TidEntry() { free(name); }
 
     const pid_t&getKey() const { return tid; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return name; }
 
-    inline void add(pid_t t) {
+    inline void add(pid_t incomingTid) {
         if (name && !fast<strncmp>(name, "zygote", 6)) {
             free(name);
             name = NULL;
         }
         if (!name) {
-            char *n = android::tidToName(t);
-            if (n) {
-                name = n;
-            }
+            name = android::tidToName(incomingTid);
         }
     }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (getUid() != u) {
-            uid = u;
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (getUid() != incomingUid) {
+            uid = incomingUid;
             free(name);
-            name = android::tidToName(e->getTid());
+            name = android::tidToName(element->getTid());
         } else {
-            add(e->getTid());
+            add(element->getTid());
         }
-        EntryBaseDropped::add(e);
+        EntryBaseDropped::add(element);
     }
+
+    std::string formatHeader(const std::string &name, log_id_t id) const;
+    std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
 struct TagEntry : public EntryBase {
     const uint32_t tag;
     uid_t uid;
 
-    TagEntry(LogBufferElement *e):
-        EntryBase(e),
-        tag(e->getTag()),
-        uid(e->getUid()) { }
+    TagEntry(LogBufferElement *element):
+            EntryBase(element),
+            tag(element->getTag()),
+            uid(element->getUid()) {
+    }
 
     const uint32_t&getKey() const { return tag; }
     const uid_t&getUid() const { return uid; }
     const char*getName() const { return android::tagToName(tag); }
 
-    inline void add(LogBufferElement *e) {
-        uid_t u = e->getUid();
-        if (uid != u) {
+    inline void add(LogBufferElement *element) {
+        uid_t incomingUid = element->getUid();
+        if (uid != incomingUid) {
             uid = -1;
         }
-        EntryBase::add(e);
+        EntryBase::add(element);
     }
+
+    std::string formatHeader(const std::string &name, log_id_t id) const;
+    std::string format(const LogStatistics &stat, log_id_t id) const;
 };
 
 // Log Statistics
@@ -324,7 +406,9 @@
     // Correct for merging two entries referencing dropped content
     void erase(LogBufferElement *e) { --mElements[e->getLogId()]; }
 
-    std::unique_ptr<const UidEntry *[]> sort(size_t n, log_id i) { return uidTable[i].sort(n); }
+    std::unique_ptr<const UidEntry *[]> sort(size_t len, log_id id) {
+        return uidTable[id].sort(len);
+    }
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const { return mSizes[id]; }
@@ -332,12 +416,12 @@
     size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
     size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
 
-    std::string format(uid_t uid, unsigned int logMask);
+    std::string format(uid_t uid, unsigned int logMask) const;
 
     // helper (must be locked directly or implicitly by mLogElementsLock)
-    char *pidToName(pid_t pid);
+    const char *pidToName(pid_t pid) const;
     uid_t pidToUid(pid_t pid);
-    char *uidToName(uid_t uid);
+    const char *uidToName(uid_t uid) const;
 };
 
 #endif // _LOGD_LOG_STATISTICS_H__
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index afb45da..3deb7d3 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -74,7 +74,7 @@
   libmetrics \
   libprotobuf-cpp-lite \
   librootdev \
-  libweaved-client \
+  libweaved \
 
 # Shared library for metrics.
 # ========================================================
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index f83c5d4..2ea5bbd 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -283,11 +283,15 @@
       return EX_UNAVAILABLE;
     }
 
-    weaved_object_mgr_.reset(new com::android::Weave::ObjectManagerProxy{bus_});
-    weaved_object_mgr_->SetCommandAddedCallback(
-        base::Bind(&MetricsDaemon::OnWeaveCommand, base::Unretained(this)));
-    weaved_object_mgr_->SetManagerAddedCallback(
+    device_ = weaved::Device::CreateInstance(
+        bus_,
         base::Bind(&MetricsDaemon::UpdateWeaveState, base::Unretained(this)));
+    device_->AddCommandHandler(
+        "_metrics._enableAnalyticsReporting",
+        base::Bind(&MetricsDaemon::OnEnableMetrics, base::Unretained(this)));
+    device_->AddCommandHandler(
+        "_metrics._disableAnalyticsReporting",
+        base::Bind(&MetricsDaemon::OnDisableMetrics, base::Unretained(this)));
   }
 
   base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
@@ -325,20 +329,11 @@
   chromeos::DBusDaemon::OnShutdown(return_code);
 }
 
-void MetricsDaemon::OnWeaveCommand(CommandProxy* command) {
-  if (command->state() != "queued") {
+void MetricsDaemon::OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd) {
+  auto command = cmd.lock();
+  if (!command)
     return;
-  }
 
-  VLOG(1) << "received weave command: " << command->name();
-  if (command->name() == "_metrics._enableAnalyticsReporting") {
-    OnEnableMetrics(command);
-  } else if (command->name() == "_metrics._disableAnalyticsReporting") {
-    OnDisableMetrics(command);
-  }
-}
-
-void MetricsDaemon::OnEnableMetrics(CommandProxy* command) {
   if (base::WriteFile(metrics_directory_.Append(metrics::kConsentFileName),
                       "", 0) != 0) {
     PLOG(ERROR) << "Could not create the consent file.";
@@ -347,11 +342,16 @@
     return;
   }
 
-  NotifyStateChanged();
+  UpdateWeaveState();
   command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::OnDisableMetrics(CommandProxy* command) {
+void MetricsDaemon::OnDisableMetrics(
+    const std::weak_ptr<weaved::Command>& cmd) {
+  auto command = cmd.lock();
+  if (!command)
+    return;
+
   if (!base::DeleteFile(metrics_directory_.Append(metrics::kConsentFileName),
                         false)) {
     PLOG(ERROR) << "Could not delete the consent file.";
@@ -360,23 +360,20 @@
     return;
   }
 
-  NotifyStateChanged();
+  UpdateWeaveState();
   command->Complete({}, nullptr);
 }
 
-void MetricsDaemon::NotifyStateChanged() {
-  ManagerProxy* manager = weaved_object_mgr_->GetManagerProxy();
-  if (manager)
-    UpdateWeaveState(manager);
-}
+void MetricsDaemon::UpdateWeaveState() {
+  if (!device_)
+    return;
 
-void MetricsDaemon::UpdateWeaveState(ManagerProxy* manager) {
   chromeos::VariantDictionary state_change{
     { "_metrics._AnalyticsReportingState",
       metrics_lib_->AreMetricsEnabled() ? "enabled" : "disabled" }
   };
 
-  if (!manager->UpdateState(state_change, nullptr)) {
+  if (!device_->SetStateProperties(state_change, nullptr)) {
     LOG(ERROR) << "failed to update weave's state";
   }
 }
diff --git a/metricsd/metrics_daemon.h b/metricsd/metrics_daemon.h
index 0a8f6a5..146108a 100644
--- a/metricsd/metrics_daemon.h
+++ b/metricsd/metrics_daemon.h
@@ -26,8 +26,9 @@
 #include <base/files/file_path.h>
 #include <base/memory/scoped_ptr.h>
 #include <base/time/time.h>
-#include <buffet/dbus-proxies.h>
 #include <chromeos/daemons/dbus_daemon.h>
+#include <libweaved/command.h>
+#include <libweaved/device.h>
 #include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
 #include "collectors/averaged_statistics_collector.h"
@@ -122,20 +123,14 @@
                                          DBusMessage* message,
                                          void* user_data);
 
-  // Callback for Weave commands.
-  void OnWeaveCommand(com::android::Weave::CommandProxy* command);
-
   // Enables metrics reporting.
-  void OnEnableMetrics(com::android::Weave::CommandProxy* command);
+  void OnEnableMetrics(const std::weak_ptr<weaved::Command>& cmd);
 
   // Disables metrics reporting.
-  void OnDisableMetrics(com::android::Weave::CommandProxy* command);
+  void OnDisableMetrics(const std::weak_ptr<weaved::Command>& cmd);
 
   // Updates the weave device state.
-  void UpdateWeaveState(com::android::Weave::ManagerProxy* manager);
-
-  // Tells Weave that the state has changed.
-  void NotifyStateChanged();
+  void UpdateWeaveState();
 
   // Updates the active use time and logs time between user-space
   // process crashes.
@@ -317,7 +312,7 @@
   std::string server_;
 
   scoped_ptr<UploadService> upload_service_;
-  scoped_ptr<com::android::Weave::ObjectManagerProxy> weaved_object_mgr_;
+  std::unique_ptr<weaved::Device> device_;
 };
 
 #endif  // METRICS_METRICS_DAEMON_H_