logd: Drop the LogStatistics dependency on LogBufferElement

Other log buffers may not use LogBufferElement, so we should decouple
the two classes.  This uses an intermediate LogStatisticsElement
structs instead of passing a large number of parameters to each
function.

This additionally moves IsBinary() and the GetTag() functions out into
LogUtils.h since they can be used generically by other users.

Test: logging unit tests
Change-Id: I71f53257342c067bcccd5aa00bae47f714cd7c66
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
index c2e89fc..62c8629 100644
--- a/logd/ChattyLogBuffer.cpp
+++ b/logd/ChattyLogBuffer.cpp
@@ -74,7 +74,8 @@
     }
 
     // audit message (except sequence number) identical?
-    if (last.IsBinary() && lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
+    if (IsBinary(last.log_id()) &&
+        lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
         lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t))) {
         if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) {
             return DIFFERENT;
@@ -205,9 +206,9 @@
 #endif
 
     if (coalesce) {
-        stats()->Erase(element);
+        stats()->Erase(element.ToLogStatisticsElement());
     } else {
-        stats()->Subtract(element);
+        stats()->Subtract(element.ToLogStatisticsElement());
     }
 
     it = SimpleLogBuffer::Erase(it);
@@ -533,7 +534,7 @@
             if (leading) {
                 it = Erase(it);
             } else {
-                stats()->Drop(element);
+                stats()->Drop(element.ToLogStatisticsElement());
                 element.SetDropped(1);
                 if (last.coalesce(&element, 1)) {
                     it = Erase(it, true);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 172a757..ef9f1cf 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -86,7 +86,7 @@
 
 uint32_t LogBufferElement::GetTag() const {
     // Binary buffers have no tag.
-    if (!IsBinary()) {
+    if (!IsBinary(log_id())) {
         return 0;
     }
 
@@ -95,12 +95,21 @@
         return tag_;
     }
 
-    // For non-dropped messages, we get the tag from the message header itself.
-    if (msg_len_ < sizeof(android_event_header_t)) {
-        return 0;
-    }
+    return MsgToTag(msg(), msg_len());
+}
 
-    return reinterpret_cast<const android_event_header_t*>(msg_)->tag;
+LogStatisticsElement LogBufferElement::ToLogStatisticsElement() const {
+    return LogStatisticsElement{
+            .uid = uid(),
+            .pid = pid(),
+            .tid = tid(),
+            .tag = GetTag(),
+            .realtime = realtime(),
+            .msg = msg(),
+            .msg_len = msg_len(),
+            .dropped_count = dropped_count(),
+            .log_id = log_id(),
+    };
 }
 
 uint16_t LogBufferElement::SetDropped(uint16_t value) {
@@ -218,7 +227,7 @@
                           type, dropped_count(), (dropped_count() > 1) ? "s" : "");
 
     size_t hdrLen;
-    if (IsBinary()) {
+    if (IsBinary(log_id())) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -232,7 +241,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if (IsBinary()) {
+    if (IsBinary(log_id())) {
         android_log_event_string_t* event =
             reinterpret_cast<android_log_event_string_t*>(buffer);
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 5b13e32..fd5d88f 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -24,7 +24,7 @@
 
 #include "LogWriter.h"
 
-class LogStatistics;
+#include "LogStatistics.h"
 
 #define EXPIRE_HOUR_THRESHOLD 24  // Only expire chatty UID logs to preserve
                                   // non-chatty UIDs less than this age in hours
@@ -40,13 +40,13 @@
     LogBufferElement(LogBufferElement&& elem);
     ~LogBufferElement();
 
-    bool IsBinary() const { return (log_id_ == LOG_ID_EVENTS) || (log_id_ == LOG_ID_SECURITY); }
-
     uint32_t GetTag() const;
     uint16_t SetDropped(uint16_t value);
 
     bool FlushTo(LogWriter* writer, LogStatistics* parent, bool lastSame);
 
+    LogStatisticsElement ToLogStatisticsElement() const;
+
     log_id_t log_id() const { return static_cast<log_id_t>(log_id_); }
     uid_t uid() const { return uid_; }
     pid_t pid() const { return pid_; }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index a2acab7..04fd59d 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -29,6 +29,8 @@
 
 #include <private/android_logger.h>
 
+#include "LogBufferElement.h"
+
 static const uint64_t hourSec = 60 * 60;
 static const uint64_t monthSec = 31 * 24 * hourSec;
 
@@ -87,10 +89,10 @@
     ++mElementsTotal[log_id];
 }
 
-void LogStatistics::Add(const LogBufferElement& element) {
+void LogStatistics::Add(const LogStatisticsElement& element) {
     auto lock = std::lock_guard{lock_};
-    log_id_t log_id = element.log_id();
-    uint16_t size = element.msg_len();
+    log_id_t log_id = element.log_id;
+    uint16_t size = element.msg_len;
     mSizes[log_id] += size;
     ++mElements[log_id];
 
@@ -99,7 +101,7 @@
     // evaluated and trimmed, thus recording size and number of
     // elements, but we must recognize the manufactured dropped
     // entry as not contributing to the lifetime totals.
-    if (element.dropped_count()) {
+    if (element.dropped_count) {
         ++mDroppedElements[log_id];
     } else {
         mSizesTotal[log_id] += size;
@@ -107,7 +109,7 @@
         ++mElementsTotal[log_id];
     }
 
-    log_time stamp(element.realtime());
+    log_time stamp(element.realtime);
     if (mNewest[log_id] < stamp) {
         // A major time update invalidates the statistics :-(
         log_time diff = stamp - mNewest[log_id];
@@ -132,19 +134,19 @@
         return;
     }
 
-    uidTable[log_id].Add(element.uid(), element);
-    if (element.uid() == AID_SYSTEM) {
-        pidSystemTable[log_id].Add(element.pid(), element);
+    uidTable[log_id].Add(element.uid, element);
+    if (element.uid == AID_SYSTEM) {
+        pidSystemTable[log_id].Add(element.pid, element);
     }
 
     if (!enable) {
         return;
     }
 
-    pidTable.Add(element.pid(), element);
-    tidTable.Add(element.tid(), element);
+    pidTable.Add(element.pid, element);
+    tidTable.Add(element.tid, element);
 
-    uint32_t tag = element.GetTag();
+    uint32_t tag = element.tag;
     if (tag) {
         if (log_id == LOG_ID_SECURITY) {
             securityTagTable.Add(tag, element);
@@ -153,42 +155,42 @@
         }
     }
 
-    if (!element.dropped_count()) {
+    if (!element.dropped_count) {
         tagNameTable.Add(TagNameKey(element), element);
     }
 }
 
-void LogStatistics::Subtract(const LogBufferElement& element) {
+void LogStatistics::Subtract(const LogStatisticsElement& element) {
     auto lock = std::lock_guard{lock_};
-    log_id_t log_id = element.log_id();
-    uint16_t size = element.msg_len();
+    log_id_t log_id = element.log_id;
+    uint16_t size = element.msg_len;
     mSizes[log_id] -= size;
     --mElements[log_id];
-    if (element.dropped_count()) {
+    if (element.dropped_count) {
         --mDroppedElements[log_id];
     }
 
-    if (mOldest[log_id] < element.realtime()) {
-        mOldest[log_id] = element.realtime();
+    if (mOldest[log_id] < element.realtime) {
+        mOldest[log_id] = element.realtime;
     }
 
     if (log_id == LOG_ID_KERNEL) {
         return;
     }
 
-    uidTable[log_id].Subtract(element.uid(), element);
-    if (element.uid() == AID_SYSTEM) {
-        pidSystemTable[log_id].Subtract(element.pid(), element);
+    uidTable[log_id].Subtract(element.uid, element);
+    if (element.uid == AID_SYSTEM) {
+        pidSystemTable[log_id].Subtract(element.pid, element);
     }
 
     if (!enable) {
         return;
     }
 
-    pidTable.Subtract(element.pid(), element);
-    tidTable.Subtract(element.tid(), element);
+    pidTable.Subtract(element.pid, element);
+    tidTable.Subtract(element.tid, element);
 
-    uint32_t tag = element.GetTag();
+    uint32_t tag = element.tag;
     if (tag) {
         if (log_id == LOG_ID_SECURITY) {
             securityTagTable.Subtract(tag, element);
@@ -197,37 +199,37 @@
         }
     }
 
-    if (!element.dropped_count()) {
+    if (!element.dropped_count) {
         tagNameTable.Subtract(TagNameKey(element), element);
     }
 }
 
 // Atomically set an entry to drop
 // entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::Drop(const LogBufferElement& element) {
+void LogStatistics::Drop(const LogStatisticsElement& element) {
     auto lock = std::lock_guard{lock_};
-    log_id_t log_id = element.log_id();
-    uint16_t size = element.msg_len();
+    log_id_t log_id = element.log_id;
+    uint16_t size = element.msg_len;
     mSizes[log_id] -= size;
     ++mDroppedElements[log_id];
 
-    if (mNewestDropped[log_id] < element.realtime()) {
-        mNewestDropped[log_id] = element.realtime();
+    if (mNewestDropped[log_id] < element.realtime) {
+        mNewestDropped[log_id] = element.realtime;
     }
 
-    uidTable[log_id].Drop(element.uid(), element);
-    if (element.uid() == AID_SYSTEM) {
-        pidSystemTable[log_id].Drop(element.pid(), element);
+    uidTable[log_id].Drop(element.uid, element);
+    if (element.uid == AID_SYSTEM) {
+        pidSystemTable[log_id].Drop(element.pid, element);
     }
 
     if (!enable) {
         return;
     }
 
-    pidTable.Drop(element.pid(), element);
-    tidTable.Drop(element.tid(), element);
+    pidTable.Drop(element.pid, element);
+    tidTable.Drop(element.tid, element);
 
-    uint32_t tag = element.GetTag();
+    uint32_t tag = element.tag;
     if (tag) {
         if (log_id == LOG_ID_SECURITY) {
             securityTagTable.Drop(tag, element);
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6a46adb..33a4d63 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -38,7 +38,6 @@
 #include <private/android_filesystem_config.h>
 #include <utils/FastStrcmp.h>
 
-#include "LogBufferElement.h"
 #include "LogUtils.h"
 
 #define log_id_for_each(i) \
@@ -46,6 +45,18 @@
 
 class LogStatistics;
 
+struct LogStatisticsElement {
+    uid_t uid;
+    pid_t pid;
+    pid_t tid;
+    uint32_t tag;
+    log_time realtime;
+    const char* msg;
+    uint16_t msg_len;
+    uint16_t dropped_count;
+    log_id_t log_id;
+};
+
 template <typename TKey, typename TEntry>
 class LogHashtable {
     std::unordered_map<TKey, TEntry> map;
@@ -113,7 +124,7 @@
         }
     }
 
-    iterator Add(const TKey& key, const LogBufferElement& element) {
+    iterator Add(const TKey& key, const LogStatisticsElement& element) {
         iterator it = map.find(key);
         if (it == map.end()) {
             it = map.insert(std::make_pair(key, TEntry(element))).first;
@@ -133,14 +144,14 @@
         return it;
     }
 
-    void Subtract(const TKey& key, const LogBufferElement& element) {
+    void Subtract(const TKey& key, const LogStatisticsElement& element) {
         iterator it = map.find(key);
         if (it != map.end() && it->second.Subtract(element)) {
             map.erase(it);
         }
     }
 
-    void Drop(const TKey& key, const LogBufferElement& element) {
+    void Drop(const TKey& key, const LogStatisticsElement& element) {
         iterator it = map.find(key);
         if (it != map.end()) {
             it->second.Drop(element);
@@ -156,13 +167,13 @@
 class EntryBase {
   public:
     EntryBase() : size_(0) {}
-    explicit EntryBase(const LogBufferElement& element) : size_(element.msg_len()) {}
+    explicit EntryBase(const LogStatisticsElement& element) : size_(element.msg_len) {}
 
     size_t getSizes() const { return size_; }
 
-    void Add(const LogBufferElement& element) { size_ += element.msg_len(); }
-    bool Subtract(const LogBufferElement& element) {
-        size_ -= element.msg_len();
+    void Add(const LogStatisticsElement& element) { size_ += element.msg_len; }
+    bool Subtract(const LogStatisticsElement& element) {
+        size_ -= element.msg_len;
         return !size_;
     }
 
@@ -193,20 +204,20 @@
 class EntryBaseDropped : public EntryBase {
   public:
     EntryBaseDropped() : dropped_(0) {}
-    explicit EntryBaseDropped(const LogBufferElement& element)
-        : EntryBase(element), dropped_(element.dropped_count()) {}
+    explicit EntryBaseDropped(const LogStatisticsElement& element)
+        : EntryBase(element), dropped_(element.dropped_count) {}
 
     size_t dropped_count() const { return dropped_; }
 
-    void Add(const LogBufferElement& element) {
-        dropped_ += element.dropped_count();
+    void Add(const LogStatisticsElement& element) {
+        dropped_ += element.dropped_count;
         EntryBase::Add(element);
     }
-    bool Subtract(const LogBufferElement& element) {
-        dropped_ -= element.dropped_count();
+    bool Subtract(const LogStatisticsElement& element) {
+        dropped_ -= element.dropped_count;
         return EntryBase::Subtract(element) && !dropped_;
     }
-    void Drop(const LogBufferElement& element) {
+    void Drop(const LogStatisticsElement& element) {
         dropped_ += 1;
         EntryBase::Subtract(element);
     }
@@ -217,15 +228,15 @@
 
 class UidEntry : public EntryBaseDropped {
   public:
-    explicit UidEntry(const LogBufferElement& element)
-        : EntryBaseDropped(element), uid_(element.uid()), pid_(element.pid()) {}
+    explicit UidEntry(const LogStatisticsElement& element)
+        : EntryBaseDropped(element), uid_(element.uid), pid_(element.pid) {}
 
     uid_t key() const { return uid_; }
     uid_t uid() const { return key(); }
     pid_t pid() const { return pid_; }
 
-    void Add(const LogBufferElement& element) {
-        if (pid_ != element.pid()) {
+    void Add(const LogStatisticsElement& element) {
+        if (pid_ != element.pid) {
             pid_ = -1;
         }
         EntryBaseDropped::Add(element);
@@ -250,10 +261,10 @@
           pid_(pid),
           uid_(android::pidToUid(pid)),
           name_(android::pidToName(pid)) {}
-    explicit PidEntry(const LogBufferElement& element)
+    explicit PidEntry(const LogStatisticsElement& element)
         : EntryBaseDropped(element),
-          pid_(element.pid()),
-          uid_(element.uid()),
+          pid_(element.pid),
+          uid_(element.uid),
           name_(android::pidToName(pid_)) {}
     PidEntry(const PidEntry& element)
         : EntryBaseDropped(element),
@@ -277,14 +288,14 @@
         }
     }
 
-    void Add(const LogBufferElement& element) {
-        uid_t incoming_uid = element.uid();
+    void Add(const LogStatisticsElement& element) {
+        uid_t incoming_uid = element.uid;
         if (uid() != incoming_uid) {
             uid_ = incoming_uid;
             free(name_);
-            name_ = android::pidToName(element.pid());
+            name_ = android::pidToName(element.pid);
         } else {
-            Add(element.pid());
+            Add(element.pid);
         }
         EntryBaseDropped::Add(element);
     }
@@ -306,11 +317,11 @@
           pid_(pid),
           uid_(android::pidToUid(tid)),
           name_(android::tidToName(tid)) {}
-    explicit TidEntry(const LogBufferElement& element)
+    explicit TidEntry(const LogStatisticsElement& element)
         : EntryBaseDropped(element),
-          tid_(element.tid()),
-          pid_(element.pid()),
-          uid_(element.uid()),
+          tid_(element.tid),
+          pid_(element.pid),
+          uid_(element.uid),
           name_(android::tidToName(tid_)) {}
     TidEntry(const TidEntry& element)
         : EntryBaseDropped(element),
@@ -336,16 +347,16 @@
         }
     }
 
-    void Add(const LogBufferElement& element) {
-        uid_t incoming_uid = element.uid();
-        pid_t incoming_pid = element.pid();
+    void Add(const LogStatisticsElement& element) {
+        uid_t incoming_uid = element.uid;
+        pid_t incoming_pid = element.pid;
         if (uid() != incoming_uid || pid() != incoming_pid) {
             uid_ = incoming_uid;
             pid_ = incoming_pid;
             free(name_);
-            name_ = android::tidToName(element.tid());
+            name_ = android::tidToName(element.tid);
         } else {
-            Add(element.tid());
+            Add(element.tid);
         }
         EntryBaseDropped::Add(element);
     }
@@ -362,22 +373,19 @@
 
 class TagEntry : public EntryBaseDropped {
   public:
-    explicit TagEntry(const LogBufferElement& element)
-        : EntryBaseDropped(element),
-          tag_(element.GetTag()),
-          pid_(element.pid()),
-          uid_(element.uid()) {}
+    explicit TagEntry(const LogStatisticsElement& element)
+        : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
 
     uint32_t key() const { return tag_; }
     pid_t pid() const { return pid_; }
     uid_t uid() const { return uid_; }
     const char* name() const { return android::tagToName(tag_); }
 
-    void Add(const LogBufferElement& element) {
-        if (uid_ != element.uid()) {
+    void Add(const LogStatisticsElement& element) {
+        if (uid_ != element.uid) {
             uid_ = -1;
         }
-        if (pid_ != element.pid()) {
+        if (pid_ != element.pid) {
             pid_ = -1;
         }
         EntryBaseDropped::Add(element);
@@ -396,9 +404,10 @@
     std::string* alloc;
     std::string_view name;  // Saves space if const char*
 
-    explicit TagNameKey(const LogBufferElement& element) : alloc(nullptr), name("", strlen("")) {
-        if (element.IsBinary()) {
-            uint32_t tag = element.GetTag();
+    explicit TagNameKey(const LogStatisticsElement& element)
+        : alloc(nullptr), name("", strlen("")) {
+        if (IsBinary(element.log_id)) {
+            uint32_t tag = element.tag;
             if (tag) {
                 const char* cp = android::tagToName(tag);
                 if (cp) {
@@ -412,13 +421,13 @@
             name = std::string_view(alloc->c_str(), alloc->size());
             return;
         }
-        const char* msg = element.msg();
+        const char* msg = element.msg;
         if (!msg) {
             name = std::string_view("chatty", strlen("chatty"));
             return;
         }
         ++msg;
-        uint16_t len = element.msg_len();
+        uint16_t len = element.msg_len;
         len = (len <= 1) ? 0 : strnlen(msg, len - 1);
         if (!len) {
             name = std::string_view("<NULL>", strlen("<NULL>"));
@@ -480,11 +489,11 @@
 
 class TagNameEntry : public EntryBase {
   public:
-    explicit TagNameEntry(const LogBufferElement& element)
+    explicit TagNameEntry(const LogStatisticsElement& element)
         : EntryBase(element),
-          tid_(element.tid()),
-          pid_(element.pid()),
-          uid_(element.uid()),
+          tid_(element.tid),
+          pid_(element.pid),
+          uid_(element.uid),
           name_(element) {}
 
     const TagNameKey& key() const { return name_; }
@@ -494,14 +503,14 @@
     const char* name() const { return name_.data(); }
     size_t getNameAllocLength() const { return name_.getAllocLength(); }
 
-    void Add(const LogBufferElement& element) {
-        if (uid_ != element.uid()) {
+    void Add(const LogStatisticsElement& element) {
+        if (uid_ != element.uid) {
             uid_ = -1;
         }
-        if (pid_ != element.pid()) {
+        if (pid_ != element.pid) {
             pid_ = -1;
         }
-        if (tid_ != element.tid()) {
+        if (tid_ != element.tid) {
             tid_ = -1;
         }
         EntryBase::Add(element);
@@ -590,14 +599,14 @@
     LogStatistics(bool enable_statistics);
 
     void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
-    void Add(const LogBufferElement& entry) EXCLUDES(lock_);
-    void Subtract(const LogBufferElement& entry) EXCLUDES(lock_);
+    void Add(const LogStatisticsElement& entry) EXCLUDES(lock_);
+    void Subtract(const LogStatisticsElement& entry) EXCLUDES(lock_);
     // entry->setDropped(1) must follow this call
-    void Drop(const LogBufferElement& entry) EXCLUDES(lock_);
+    void Drop(const LogStatisticsElement& entry) EXCLUDES(lock_);
     // Correct for coalescing two entries referencing dropped content
-    void Erase(const LogBufferElement& element) EXCLUDES(lock_) {
+    void Erase(const LogStatisticsElement& element) EXCLUDES(lock_) {
         auto lock = std::lock_guard{lock_};
-        log_id_t log_id = element.log_id();
+        log_id_t log_id = element.log_id;
         --mElements[log_id];
         --mDroppedElements[log_id];
     }
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index c472167..96aa1d3 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -60,6 +60,20 @@
 }
 }
 
+// Returns true if the log buffer is meant for binary logs.
+static inline bool IsBinary(log_id_t log_id) {
+    return log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY;
+}
+
+// Returns the numeric log tag for binary log messages.
+static inline uint32_t MsgToTag(const char* msg, uint16_t msg_len) {
+    if (msg_len < sizeof(android_event_header_t)) {
+        return 0;
+    }
+
+    return reinterpret_cast<const android_event_header_t*>(msg)->tag;
+}
+
 static inline bool worstUidEnabledForLogid(log_id_t id) {
     return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
            (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
index 5ab8e09..b4b3546 100644
--- a/logd/SimpleLogBuffer.cpp
+++ b/logd/SimpleLogBuffer.cpp
@@ -61,11 +61,8 @@
     int prio = ANDROID_LOG_INFO;
     const char* tag = nullptr;
     size_t tag_len = 0;
-    if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
-        if (len < sizeof(android_event_header_t)) {
-            return false;
-        }
-        int32_t numeric_tag = reinterpret_cast<const android_event_header_t*>(msg)->tag;
+    if (IsBinary(log_id)) {
+        int32_t numeric_tag = MsgToTag(msg, len);
         tag = tags_->tagToName(numeric_tag);
         if (tag) {
             tag_len = strlen(tag);
@@ -105,7 +102,7 @@
     log_id_t log_id = elem.log_id();
 
     logs_.emplace_back(std::move(elem));
-    stats_->Add(logs_.back());
+    stats_->Add(logs_.back().ToLogStatisticsElement());
     MaybePrune(log_id);
     reader_list_->NotifyNewLog(1 << log_id);
 }
@@ -317,7 +314,7 @@
             return true;
         }
 
-        stats_->Subtract(element);
+        stats_->Subtract(element.ToLogStatisticsElement());
         it = Erase(it);
         if (--prune_rows == 0) {
             return false;