logd: remove LogFindWorst

LogStatistics relies on LogBuffer's lock for thread safety, but that
will be cleaned up in future CLs.  It won't be possible to return a
'LogFindWorst' object that references internal LogStatistics pointers
in a thread safe way, so we remove this and provide a more simple
interface.

This also removes unnecessary allocations; std::array of 2 or 32
entries is small enough to allocate on the stack.

Test: logging unit tests
Change-Id: I38bfcba5b08c640ffd3af5c078bc716688f6edf8
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 2cb0c5e..ad391e5 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -663,19 +663,14 @@
             // Calculate threshold as 12.5% of available storage
             size_t threshold = log_buffer_size(id) / 8;
 
-            if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
-                stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
-                    .findWorst(worst, worst_sizes, second_worst_sizes,
-                               threshold);
+            if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
+                stats.WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
                 // per-pid filter for AID_SYSTEM sources is too complex
             } else {
-                stats.sort(AID_ROOT, (pid_t)0, 2, id)
-                    .findWorst(worst, worst_sizes, second_worst_sizes,
-                               threshold);
+                stats.WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
 
-                if ((worst == AID_SYSTEM) && prune_->worstPidOfSystemEnabled()) {
-                    stats.sortPids(worst, (pid_t)0, 2, id)
-                        .findWorst(worstPid, worst_sizes, second_worst_sizes);
+                if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
+                    stats.WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
                 }
             }
         }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 431b778..4c4c1db 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -297,6 +297,49 @@
     return name;
 }
 
+template <typename TKey, typename TEntry>
+void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+                                          int* worst, size_t* worst_sizes,
+                                          size_t* second_worst_sizes) {
+    std::array<const TEntry*, 2> max_entries;
+    table.MaxEntries(AID_ROOT, 0, &max_entries);
+    if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+        return;
+    }
+    *worst_sizes = max_entries[0]->getSizes();
+    // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
+    // 100 characters.
+    if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->getDropped())) {
+        *worst = max_entries[0]->getKey();
+        *second_worst_sizes = max_entries[1]->getSizes();
+        if (*second_worst_sizes < threshold) {
+            *second_worst_sizes = threshold;
+        }
+    }
+}
+
+void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+                                 size_t* second_worst_sizes) {
+    WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+                                 size_t* second_worst_sizes) {
+    WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
+}
+
+void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+                                       size_t* second_worst_sizes) {
+    std::array<const PidEntry*, 2> max_entries;
+    pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
+    if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+        return;
+    }
+
+    *worst = max_entries[0]->getKey();
+    *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
+}
+
 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(),
@@ -401,12 +444,9 @@
     }
 
     static const size_t maximum_sorted_entries = 32;
-    std::unique_ptr<const PidEntry* []> sorted =
-        stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
+    std::array<const PidEntry*, maximum_sorted_entries> sorted;
+    stat.pidSystemTable[id].MaxEntries(uid, 0, &sorted);
 
-    if (!sorted.get()) {
-        return output;
-    }
     std::string byPid;
     size_t index;
     bool hasDropped = false;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 0782de3..ed9002a 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _LOGD_LOG_STATISTICS_H__
-#define _LOGD_LOG_STATISTICS_H__
+#pragma once
 
 #include <ctype.h>
 #include <inttypes.h>
@@ -25,6 +24,7 @@
 #include <sys/types.h>
 
 #include <algorithm>  // std::max
+#include <array>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -79,16 +79,12 @@
     typedef
         typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
 
-    std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
-                                           size_t len) const {
-        if (!len) {
-            std::unique_ptr<const TEntry* []> sorted(nullptr);
-            return sorted;
-        }
-
-        const TEntry** retval = new const TEntry*[len];
-        memset(retval, 0, sizeof(*retval) * len);
-
+    // Returns a sorted array of up to len highest entries sorted by size.  If fewer than len
+    // entries are found, their positions are set to nullptr.
+    template <size_t len>
+    void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
+        auto& retval = *out;
+        retval.fill(nullptr);
         for (const_iterator it = map.begin(); it != map.end(); ++it) {
             const TEntry& entry = it->second;
 
@@ -113,8 +109,6 @@
                 retval[index] = &entry;
             }
         }
-        std::unique_ptr<const TEntry* []> sorted(retval);
-        return sorted;
     }
 
     inline iterator add(const TKey& key, const LogBufferElement* element) {
@@ -176,11 +170,8 @@
                        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(uid, pid, maximum_sorted_entries);
-        if (!sorted.get()) {
-            return output;
-        }
+        std::array<const TEntry*, maximum_sorted_entries> sorted;
+        MaxEntries(uid, pid, &sorted);
         bool headerPrinted = false;
         for (size_t index = 0; index < maximum_sorted_entries; ++index) {
             const TEntry* entry = sorted[index];
@@ -627,41 +618,6 @@
     std::string format(const LogStatistics& stat, log_id_t id) const;
 };
 
-template <typename TEntry>
-class LogFindWorst {
-    std::unique_ptr<const TEntry* []> sorted;
-
-   public:
-    explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
-        : sorted(std::move(sorted)) {
-    }
-
-    void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
-                   size_t threshold) {
-        if (sorted.get() && sorted[0] && sorted[1]) {
-            worst_sizes = sorted[0]->getSizes();
-            if ((worst_sizes > threshold)
-                // Allow time horizon to extend roughly tenfold, assume
-                // average entry length is 100 characters.
-                && (worst_sizes > (10 * sorted[0]->getDropped()))) {
-                worst = sorted[0]->getKey();
-                second_worst_sizes = sorted[1]->getSizes();
-                if (second_worst_sizes < threshold) {
-                    second_worst_sizes = threshold;
-                }
-            }
-        }
-    }
-
-    void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
-        if (sorted.get() && sorted[0] && sorted[1]) {
-            worst = sorted[0]->getKey();
-            second_worst_sizes =
-                worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
-        }
-    }
-};
-
 // Log Statistics
 class LogStatistics {
     friend UidEntry;
@@ -748,16 +704,12 @@
         --mDroppedElements[log_id];
     }
 
-    LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
-        return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
-    }
-    LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
-                                    log_id id) {
-        return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
-    }
-    LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
-        return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
-    }
+    void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
+                      size_t* second_worst_sizes);
+    void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
+                      size_t* second_worst_sizes);
+    void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
+                            size_t* second_worst_sizes);
 
     // fast track current value by id only
     size_t sizes(log_id_t id) const {
@@ -785,6 +737,9 @@
     const char* pidToName(pid_t pid) const;
     uid_t pidToUid(pid_t pid);
     const char* uidToName(uid_t uid) const;
-};
 
-#endif  // _LOGD_LOG_STATISTICS_H__
+  private:
+    template <typename TKey, typename TEntry>
+    void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
+                               int* worst, size_t* worst_sizes, size_t* second_worst_sizes);
+};