diff options
Diffstat (limited to 'logd/LogStatistics.cpp')
-rw-r--r-- | logd/LogStatistics.cpp | 506 |
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; } |