summaryrefslogtreecommitdiff
path: root/logd/LogStatistics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'logd/LogStatistics.cpp')
-rw-r--r--logd/LogStatistics.cpp506
1 files changed, 361 insertions, 145 deletions
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 431b7784ba..87069b3ed2 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogStatistics.h"
+
#include <ctype.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -24,17 +26,46 @@
#include <unistd.h>
#include <list>
+#include <vector>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <private/android_logger.h>
-#include "LogStatistics.h"
+#include "LogBufferElement.h"
static const uint64_t hourSec = 60 * 60;
static const uint64_t monthSec = 31 * 24 * hourSec;
-size_t LogStatistics::SizesTotal;
+std::atomic<size_t> LogStatistics::SizesTotal;
+
+static std::string TagNameKey(const LogStatisticsElement& element) {
+ if (IsBinary(element.log_id)) {
+ uint32_t tag = element.tag;
+ if (tag) {
+ const char* cp = android::tagToName(tag);
+ if (cp) {
+ return std::string(cp);
+ }
+ }
+ return android::base::StringPrintf("[%" PRIu32 "]", tag);
+ }
+ const char* msg = element.msg;
+ if (!msg) {
+ return "chatty";
+ }
+ ++msg;
+ uint16_t len = element.msg_len;
+ len = (len <= 1) ? 0 : strnlen(msg, len - 1);
+ if (!len) {
+ return "<NULL>";
+ }
+ return std::string(msg, len);
+}
-LogStatistics::LogStatistics() : enable(false) {
+LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
+ std::optional<log_time> start_time)
+ : enable(enable_statistics), track_total_size_(track_total_size) {
log_time now(CLOCK_REALTIME);
log_id_for_each(id) {
mSizes[id] = 0;
@@ -42,8 +73,13 @@ LogStatistics::LogStatistics() : enable(false) {
mDroppedElements[id] = 0;
mSizesTotal[id] = 0;
mElementsTotal[id] = 0;
- mOldest[id] = now;
- mNewest[id] = now;
+ if (start_time) {
+ mOldest[id] = *start_time;
+ mNewest[id] = *start_time;
+ } else {
+ mOldest[id] = now;
+ mNewest[id] = now;
+ }
mNewestDropped[id] = now;
}
}
@@ -62,7 +98,7 @@ char* pidToName(pid_t pid) {
} else {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
- int fd = open(buffer, O_RDONLY);
+ int fd = open(buffer, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
ssize_t ret = read(fd, buffer, sizeof(buffer));
if (ret > 0) {
@@ -79,19 +115,23 @@ char* pidToName(pid_t pid) {
}
}
-void LogStatistics::addTotal(LogBufferElement* element) {
- if (element->getDropped()) return;
+void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
+ auto lock = std::lock_guard{lock_};
- log_id_t log_id = element->getLogId();
- uint16_t size = element->getMsgLen();
mSizesTotal[log_id] += size;
SizesTotal += size;
++mElementsTotal[log_id];
}
-void LogStatistics::add(LogBufferElement* element) {
- log_id_t log_id = element->getLogId();
- uint16_t size = element->getMsgLen();
+void LogStatistics::Add(LogStatisticsElement element) {
+ auto lock = std::lock_guard{lock_};
+
+ if (!track_total_size_) {
+ element.total_len = element.msg_len;
+ }
+
+ log_id_t log_id = element.log_id;
+ uint16_t size = element.total_len;
mSizes[log_id] += size;
++mElements[log_id];
@@ -100,7 +140,7 @@ void LogStatistics::add(LogBufferElement* element) {
// 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->getDropped()) {
+ if (element.dropped_count) {
++mDroppedElements[log_id];
} else {
mSizesTotal[log_id] += size;
@@ -108,7 +148,7 @@ void LogStatistics::add(LogBufferElement* element) {
++mElementsTotal[log_id];
}
- log_time stamp(element->getRealTime());
+ log_time stamp(element.realtime);
if (mNewest[log_id] < stamp) {
// A major time update invalidates the statistics :-(
log_time diff = stamp - mNewest[log_id];
@@ -133,114 +173,164 @@ void LogStatistics::add(LogBufferElement* element) {
return;
}
- uidTable[log_id].add(element->getUid(), element);
- if (element->getUid() == AID_SYSTEM) {
- pidSystemTable[log_id].add(element->getPid(), 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->getPid(), element);
- tidTable.add(element->getTid(), 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);
+ securityTagTable.Add(tag, element);
} else {
- tagTable.add(tag, element);
+ tagTable.Add(tag, element);
}
}
- if (!element->getDropped()) {
- tagNameTable.add(TagNameKey(element), element);
+ if (!element.dropped_count) {
+ tagNameTable.Add(TagNameKey(element), element);
}
}
-void LogStatistics::subtract(LogBufferElement* element) {
- log_id_t log_id = element->getLogId();
- uint16_t size = element->getMsgLen();
+void LogStatistics::Subtract(LogStatisticsElement element) {
+ auto lock = std::lock_guard{lock_};
+
+ if (!track_total_size_) {
+ element.total_len = element.msg_len;
+ }
+
+ log_id_t log_id = element.log_id;
+ uint16_t size = element.total_len;
mSizes[log_id] -= size;
--mElements[log_id];
- if (element->getDropped()) {
+ if (element.dropped_count) {
--mDroppedElements[log_id];
}
- if (mOldest[log_id] < element->getRealTime()) {
- mOldest[log_id] = element->getRealTime();
+ if (mOldest[log_id] < element.realtime) {
+ mOldest[log_id] = element.realtime;
}
if (log_id == LOG_ID_KERNEL) {
return;
}
- uidTable[log_id].subtract(element->getUid(), element);
- if (element->getUid() == AID_SYSTEM) {
- pidSystemTable[log_id].subtract(element->getPid(), 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->getPid(), element);
- tidTable.subtract(element->getTid(), 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);
+ securityTagTable.Subtract(tag, element);
} else {
- tagTable.subtract(tag, element);
+ tagTable.Subtract(tag, element);
}
}
- if (!element->getDropped()) {
- tagNameTable.subtract(TagNameKey(element), element);
+ 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(LogBufferElement* element) {
- log_id_t log_id = element->getLogId();
- uint16_t size = element->getMsgLen();
+void LogStatistics::Drop(LogStatisticsElement element) {
+ CHECK_EQ(element.dropped_count, 0U);
+
+ auto lock = std::lock_guard{lock_};
+ 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->getRealTime()) {
- mNewestDropped[log_id] = element->getRealTime();
+ if (mNewestDropped[log_id] < element.realtime) {
+ mNewestDropped[log_id] = element.realtime;
}
- uidTable[log_id].drop(element->getUid(), element);
- if (element->getUid() == AID_SYSTEM) {
- pidSystemTable[log_id].drop(element->getPid(), 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->getPid(), element);
- tidTable.drop(element->getTid(), 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);
+ securityTagTable.Drop(tag, element);
} else {
- tagTable.drop(tag, element);
+ tagTable.Drop(tag, element);
}
}
- tagNameTable.subtract(TagNameKey(element), element);
+ tagNameTable.Subtract(TagNameKey(element), element);
+}
+
+void LogStatistics::Erase(LogStatisticsElement element) {
+ CHECK_GT(element.dropped_count, 0U);
+ CHECK_EQ(element.msg_len, 0U);
+
+ auto lock = std::lock_guard{lock_};
+
+ if (!track_total_size_) {
+ element.total_len = 0;
+ }
+
+ log_id_t log_id = element.log_id;
+ --mElements[log_id];
+ --mDroppedElements[log_id];
+ mSizes[log_id] -= element.total_len;
+
+ uidTable[log_id].Erase(element.uid, element);
+ if (element.uid == AID_SYSTEM) {
+ pidSystemTable[log_id].Erase(element.pid, element);
+ }
+
+ if (!enable) {
+ return;
+ }
+
+ pidTable.Erase(element.pid, element);
+ tidTable.Erase(element.tid, element);
+
+ uint32_t tag = element.tag;
+ if (tag) {
+ if (log_id == LOG_ID_SECURITY) {
+ securityTagTable.Erase(tag, element);
+ } else {
+ tagTable.Erase(tag, element);
+ }
+ }
+}
+
+const char* LogStatistics::UidToName(uid_t uid) const {
+ auto lock = std::lock_guard{lock_};
+ return UidToNameLocked(uid);
}
// caller must own and free character string
-// Requires parent LogBuffer::wrlock() to be held
-const char* LogStatistics::uidToName(uid_t uid) const {
+const char* LogStatistics::UidToNameLocked(uid_t uid) const {
// Local hard coded favourites
if (uid == AID_LOGD) {
return strdup("auditd");
@@ -278,8 +368,8 @@ const char* LogStatistics::uidToName(uid_t uid) const {
++it) {
const PidEntry& entry = it->second;
- if (entry.getUid() == uid) {
- const char* nameTmp = entry.getName();
+ if (entry.uid() == uid) {
+ const char* nameTmp = entry.name();
if (nameTmp) {
if (!name) {
@@ -297,6 +387,82 @@ const char* LogStatistics::uidToName(uid_t uid) const {
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) const {
+ std::array<const TKey*, 2> max_keys;
+ std::array<const TEntry*, 2> max_entries;
+ table.MaxEntries(AID_ROOT, 0, max_keys, 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]->dropped_count())) {
+ *worst = *max_keys[0];
+ *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) const {
+ auto lock = std::lock_guard{lock_};
+ 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) const {
+ auto lock = std::lock_guard{lock_};
+ 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) const {
+ auto lock = std::lock_guard{lock_};
+ std::array<const pid_t*, 2> max_keys;
+ std::array<const PidEntry*, 2> max_entries;
+ pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
+ if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
+ return;
+ }
+
+ *worst = *max_keys[0];
+ *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
+}
+
+// Prune at most 10% of the log entries or maxPrune, whichever is less.
+bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
+ unsigned long* prune_rows) const {
+ static constexpr size_t kMinPrune = 4;
+ static constexpr size_t kMaxPrune = 256;
+
+ auto lock = std::lock_guard{lock_};
+ size_t sizes = mSizes[id];
+ if (sizes <= max_size) {
+ return false;
+ }
+ size_t size_over = sizes - ((max_size * 9) / 10);
+ size_t elements = mElements[id] - mDroppedElements[id];
+ size_t min_elements = elements / 100;
+ if (min_elements < kMinPrune) {
+ min_elements = kMinPrune;
+ }
+ *prune_rows = elements * size_over / sizes;
+ if (*prune_rows < min_elements) {
+ *prune_rows = min_elements;
+ }
+ if (*prune_rows > kMaxPrune) {
+ *prune_rows = kMaxPrune;
+ }
+
+ return true;
+}
+
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(),
@@ -308,15 +474,14 @@ std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
}
// Helper to truncate name, if too long, and add name dressings
-static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
- std::string& name, std::string& size, size_t nameLen) {
+void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
+ size_t nameLen) const {
const char* allocNameTmp = nullptr;
- if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
+ if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
if (nameTmp) {
size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
- size_t len = EntryBaseConstants::total_len -
- EntryBaseConstants::pruned_len - size.length() -
- name.length() - lenSpace - 2;
+ size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
+ lenSpace - 2;
size_t lenNameTmp = strlen(nameTmp);
while ((len < lenNameTmp) && (lenSpace > 1)) {
++len;
@@ -332,12 +497,12 @@ static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
}
}
-std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
- uid_t uid = getUid();
+std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
+ REQUIRES(stat.lock_) {
std::string name = android::base::StringPrintf("%u", uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, nullptr, uid, name, size, 6);
+ stat.FormatTmp(nullptr, uid, name, size, 6);
std::string pruned = "";
if (worstUidEnabledForLogid(id)) {
@@ -345,17 +510,17 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
for (LogStatistics::uidTable_t::const_iterator it =
stat.uidTable[id].begin();
it != stat.uidTable[id].end(); ++it) {
- totalDropped += it->second.getDropped();
+ totalDropped += it->second.dropped_count();
}
- size_t sizes = stat.sizes(id);
- size_t totalSize = stat.sizesTotal(id);
- size_t totalElements = stat.elementsTotal(id);
+ size_t sizes = stat.mSizes[id];
+ size_t totalSize = stat.mSizesTotal[id];
+ size_t totalElements = stat.mElementsTotal[id];
float totalVirtualSize =
(float)sizes + (float)totalDropped * totalSize / totalElements;
size_t entrySize = getSizes();
float virtualEntrySize = entrySize;
int realPermille = virtualEntrySize * 1000.0 / sizes;
- size_t dropped = getDropped();
+ size_t dropped = dropped_count();
if (dropped) {
pruned = android::base::StringPrintf("%zu", dropped);
virtualEntrySize += (float)dropped * totalSize / totalElements;
@@ -382,8 +547,7 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
change = android::base::StringPrintf(
"%s%d%s", prefix, (permille + 5) / 10, units);
}
- ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
- pruned.length() - change.length();
+ ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
if ((spaces <= 0) && pruned.length()) {
spaces = 1;
}
@@ -401,27 +565,25 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
}
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 pid_t*, maximum_sorted_entries> sorted_pids;
+ std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
+ stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
- if (!sorted.get()) {
- return output;
- }
std::string byPid;
size_t index;
bool hasDropped = false;
for (index = 0; index < maximum_sorted_entries; ++index) {
- const PidEntry* entry = sorted[index];
+ const PidEntry* entry = sorted_entries[index];
if (!entry) {
break;
}
if (entry->getSizes() <= (getSizes() / 100)) {
break;
}
- if (entry->getDropped()) {
+ if (entry->dropped_count()) {
hasDropped = true;
}
- byPid += entry->format(stat, id);
+ byPid += entry->format(stat, id, *sorted_pids[index]);
}
if (index > 1) { // print this only if interesting
std::string ditto("\" ");
@@ -440,17 +602,15 @@ std::string PidEntry::formatHeader(const std::string& name,
std::string("BYTES"), std::string("NUM"));
}
-std::string PidEntry::format(const LogStatistics& stat,
- log_id_t /* id */) const {
- uid_t uid = getUid();
- pid_t pid = getPid();
- std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
+std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
+ REQUIRES(stat.lock_) {
+ std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, getName(), uid, name, size, 12);
+ stat.FormatTmp(name_, uid_, name, size, 12);
std::string pruned = "";
- size_t dropped = getDropped();
+ size_t dropped = dropped_count();
if (dropped) {
pruned = android::base::StringPrintf("%zu", dropped);
}
@@ -465,16 +625,15 @@ std::string TidEntry::formatHeader(const std::string& name,
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", getTid(), uid);
+std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
+ REQUIRES(stat.lock_) {
+ std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
std::string size = android::base::StringPrintf("%zu", getSizes());
- formatTmp(stat, getName(), uid, name, size, 12);
+ stat.FormatTmp(name_, uid_, name, size, 12);
std::string pruned = "";
- size_t dropped = getDropped();
+ size_t dropped = dropped_count();
if (dropped) {
pruned = android::base::StringPrintf("%zu", dropped);
}
@@ -490,16 +649,14 @@ std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
std::string("BYTES"), std::string(isprune ? "NUM" : ""));
}
-std::string TagEntry::format(const LogStatistics& /* stat */,
- log_id_t /* id */) const {
+std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
std::string name;
- uid_t uid = getUid();
- if (uid == (uid_t)-1) {
- name = android::base::StringPrintf("%7u", getKey());
+ if (uid_ == (uid_t)-1) {
+ name = android::base::StringPrintf("%7u", key());
} else {
- name = android::base::StringPrintf("%7u/%u", getKey(), uid);
+ name = android::base::StringPrintf("%7u/%u", key(), uid_);
}
- const char* nameTmp = getName();
+ const char* nameTmp = this->name();
if (nameTmp) {
name += android::base::StringPrintf(
"%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
@@ -508,7 +665,7 @@ std::string TagEntry::format(const LogStatistics& /* stat */,
std::string size = android::base::StringPrintf("%zu", getSizes());
std::string pruned = "";
- size_t dropped = getDropped();
+ size_t dropped = dropped_count();
if (dropped) {
pruned = android::base::StringPrintf("%zu", dropped);
}
@@ -523,37 +680,33 @@ std::string TagNameEntry::formatHeader(const std::string& name,
std::string("BYTES"), std::string(""));
}
-std::string TagNameEntry::format(const LogStatistics& /* stat */,
- log_id_t /* id */) const {
+std::string TagNameEntry::format(const LogStatistics&, log_id_t,
+ const std::string& key_name) const {
std::string name;
- pid_t tid = getTid();
- pid_t pid = getPid();
std::string pidstr;
- if (pid != (pid_t)-1) {
- pidstr = android::base::StringPrintf("%u", pid);
- if ((tid != (pid_t)-1) && (tid != pid)) pidstr = "/" + pidstr;
+ if (pid_ != (pid_t)-1) {
+ pidstr = android::base::StringPrintf("%u", pid_);
+ if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
}
int len = 9 - pidstr.length();
if (len < 0) len = 0;
- if ((tid == (pid_t)-1) || (tid == pid)) {
+ if (tid_ == (pid_t)-1 || tid_ == pid_) {
name = android::base::StringPrintf("%*s", len, "");
} else {
- name = android::base::StringPrintf("%*u", len, tid);
+ name = android::base::StringPrintf("%*u", len, tid_);
}
name += pidstr;
- uid_t uid = getUid();
- if (uid != (uid_t)-1) {
- name += android::base::StringPrintf("/%u", uid);
+ if (uid_ != (uid_t)-1) {
+ name += android::base::StringPrintf("/%u", uid_);
}
std::string size = android::base::StringPrintf("%zu", getSizes());
- const char* nameTmp = getName();
+ const char* nameTmp = key_name.data();
if (nameTmp) {
size_t lenSpace = std::max(16 - name.length(), (size_t)1);
- size_t len = EntryBaseConstants::total_len -
- EntryBaseConstants::pruned_len - size.length() -
- name.length() - lenSpace - 2;
+ size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
+ lenSpace - 2;
size_t lenNameTmp = strlen(nameTmp);
while ((len < lenNameTmp) && (lenSpace > 1)) {
++len;
@@ -611,8 +764,62 @@ static std::string formatMsec(uint64_t val) {
return output;
}
-std::string LogStatistics::format(uid_t uid, pid_t pid,
- unsigned int logMask) const {
+template <typename TKey, typename TEntry>
+std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
+ pid_t pid, const std::string& name, log_id_t id) const
+ REQUIRES(lock_) {
+ static const size_t maximum_sorted_entries = 32;
+ std::string output;
+ std::array<const TKey*, maximum_sorted_entries> sorted_keys;
+ std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
+ table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
+ bool header_printed = false;
+ for (size_t index = 0; index < maximum_sorted_entries; ++index) {
+ const TEntry* entry = sorted_entries[index];
+ if (!entry) {
+ break;
+ }
+ if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
+ break;
+ }
+ if (!header_printed) {
+ output += "\n\n";
+ output += entry->formatHeader(name, id);
+ header_printed = true;
+ }
+ output += entry->format(*this, id, *sorted_keys[index]);
+ }
+ return output;
+}
+
+std::string LogStatistics::ReportInteresting() const {
+ auto lock = std::lock_guard{lock_};
+
+ std::vector<std::string> items;
+
+ log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
+
+ log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
+
+ log_id_for_each(i) {
+ items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
+ }
+
+ log_id_for_each(i) {
+ uint64_t oldest = mOldest[i].msec() / 1000;
+ uint64_t newest = mNewest[i].msec() / 1000;
+
+ int span = newest - oldest;
+
+ items.emplace_back(std::to_string(span));
+ }
+
+ return android::base::Join(items, ",");
+}
+
+std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
+ auto lock = std::lock_guard{lock_};
+
static const uint16_t spaces_total = 19;
// Report on total logging, current and for all time
@@ -642,9 +849,9 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
if (!(logMask & (1 << id))) continue;
oldLength = output.length();
if (spaces < 0) spaces = 0;
- size_t szs = sizesTotal(id);
+ size_t szs = mSizesTotal[id];
totalSize += szs;
- size_t els = elementsTotal(id);
+ size_t els = mElementsTotal[id];
totalEls += els;
output +=
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
@@ -663,11 +870,11 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
- size_t els = elements(id);
+ size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
- size_t szs = sizes(id);
+ size_t szs = mSizes[id];
totalSize += szs;
totalEls += els;
output +=
@@ -749,16 +956,24 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
- size_t els = elements(id);
+ size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
- // estimate the std::list overhead.
- static const size_t overhead =
- ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
- -sizeof(uint64_t)) +
- sizeof(std::list<LogBufferElement*>);
- size_t szs = sizes(id) + els * overhead;
+ size_t szs = 0;
+ if (overhead_[id]) {
+ szs = *overhead_[id];
+ } else if (track_total_size_) {
+ szs = mSizes[id];
+ } else {
+ // Legacy fallback for Chatty without track_total_size_
+ // Estimate the size of this element in the parent std::list<> by adding two void*'s
+ // corresponding to the next/prev pointers and aligning to 64 bit.
+ static const size_t overhead =
+ (sizeof(LogBufferElement) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) &
+ -sizeof(uint64_t);
+ szs = mSizes[id] + els * overhead;
+ }
totalSize += szs;
output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
spaces -= output.length() - oldLength;
@@ -779,39 +994,38 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
: "Logging for your UID in %s log buffer:";
- output += uidTable[id].format(*this, uid, pid, name, id);
+ output += FormatTable(uidTable[id], uid, pid, name, id);
}
if (enable) {
name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
: "Logging for this PID:";
- output += pidTable.format(*this, uid, pid, name);
+ output += FormatTable(pidTable, uid, pid, name);
name = "Chattiest TIDs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tidTable.format(*this, uid, pid, name);
+ output += FormatTable(tidTable, uid, pid, name);
}
if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
name = "Chattiest events log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
+ output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
}
if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
name = "Chattiest security log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output +=
- securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
+ output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
}
if (enable) {
name = "Chattiest TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
- output += tagNameTable.format(*this, uid, pid, name);
+ output += FormatTable(tagNameTable, uid, pid, name);
}
return output;
@@ -822,7 +1036,7 @@ namespace android {
uid_t pidToUid(pid_t pid) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
- FILE* fp = fopen(buffer, "r");
+ FILE* fp = fopen(buffer, "re");
if (fp) {
while (fgets(buffer, sizeof(buffer), fp)) {
int uid = AID_LOGD;
@@ -839,15 +1053,17 @@ uid_t pidToUid(pid_t pid) {
}
}
-uid_t LogStatistics::pidToUid(pid_t pid) {
- return pidTable.add(pid)->second.getUid();
+uid_t LogStatistics::PidToUid(pid_t pid) {
+ auto lock = std::lock_guard{lock_};
+ return pidTable.Add(pid)->second.uid();
}
// caller must free character string
-const char* LogStatistics::pidToName(pid_t pid) const {
+const char* LogStatistics::PidToName(pid_t pid) const {
+ auto lock = std::lock_guard{lock_};
// An inconvenient truth ... getName() can alter the object
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
- const char* name = writablePidTable.add(pid)->second.getName();
+ const char* name = writablePidTable.Add(pid)->second.name();
if (!name) {
return nullptr;
}