diff --git a/logd/Android.bp b/logd/Android.bp index ea1054d1b..3df59f5f4 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -54,6 +54,7 @@ cc_library_static { cflags: [ "-Wextra", + "-Wthread-safety", ] + event_flag, } diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp index 4044dc984..87402acc3 100644 --- a/logd/CommandListener.cpp +++ b/logd/CommandListener.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "CommandListener.h" + #include #include #include @@ -35,12 +37,11 @@ #include #include -#include "CommandListener.h" -#include "LogCommand.h" #include "LogUtils.h" -CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune) - : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune) { +CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, + LogStatistics* stats) + : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune), stats_(stats) { registerCmd(new ClearCmd(this)); registerCmd(new GetBufSizeCmd(this)); registerCmd(new SetBufSizeCmd(this)); @@ -148,7 +149,7 @@ int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc, return 0; } - unsigned long size = buf()->getSizeUsed((log_id_t)id); + unsigned long size = stats()->Sizes((log_id_t)id); char buf[512]; snprintf(buf, sizeof(buf), "%lu", size); cli->sendMsg(buf); @@ -209,7 +210,7 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc, } } - cli->sendMsg(PackageString(buf()->formatStatistics(uid, pid, logMask)).c_str()); + cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str()); return 0; } diff --git a/logd/CommandListener.h b/logd/CommandListener.h index c90c247cb..fd934f7c6 100644 --- a/logd/CommandListener.h +++ b/logd/CommandListener.h @@ -22,12 +22,13 @@ #include "LogCommand.h" #include "LogListener.h" #include "LogReader.h" +#include "LogStatistics.h" #include "LogTags.h" #include "LogWhiteBlackList.h" class CommandListener : public FrameworkListener { public: - CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune); + CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics); virtual ~CommandListener() {} private: @@ -36,20 +37,22 @@ class CommandListener : public FrameworkListener { LogBuffer* buf_; LogTags* tags_; PruneList* prune_; + LogStatistics* stats_; -#define LogCmd(name, command_string) \ - class name##Cmd : public LogCommand { \ - public: \ - explicit name##Cmd(CommandListener* parent) \ - : LogCommand(#command_string), parent_(parent) {} \ - virtual ~name##Cmd() {} \ - int runCommand(SocketClient* c, int argc, char** argv); \ - \ - private: \ - LogBuffer* buf() const { return parent_->buf_; } \ - LogTags* tags() const { return parent_->tags_; } \ - PruneList* prune() const { return parent_->prune_; } \ - CommandListener* parent_; \ +#define LogCmd(name, command_string) \ + class name##Cmd : public LogCommand { \ + public: \ + explicit name##Cmd(CommandListener* parent) \ + : LogCommand(#command_string), parent_(parent) {} \ + virtual ~name##Cmd() {} \ + int runCommand(SocketClient* c, int argc, char** argv); \ + \ + private: \ + LogBuffer* buf() const { return parent_->buf_; } \ + LogTags* tags() const { return parent_->tags_; } \ + PruneList* prune() const { return parent_->prune_; } \ + LogStatistics* stats() const { return parent_->stats_; } \ + CommandListener* parent_; \ } LogCmd(Clear, clear); diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index bcc187d68..6c42a289f 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "LogAudit.h" + #include #include #include @@ -34,8 +36,6 @@ #include #include -#include "LogAudit.h" -#include "LogBuffer.h" #include "LogKlog.h" #include "LogReader.h" #include "LogUtils.h" @@ -45,16 +45,15 @@ '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \ '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>' -LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg) +LogAudit::LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg, LogStatistics* stats) : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader), fdDmesg(fdDmesg), - main(__android_logger_property_get_bool("ro.logd.auditd.main", - BOOL_DEFAULT_TRUE)), - events(__android_logger_property_get_bool("ro.logd.auditd.events", - BOOL_DEFAULT_TRUE)), - initialized(false) { + main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)), + events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)), + initialized(false), + stats_(stats) { static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), 'l', 'o', @@ -211,9 +210,7 @@ int LogAudit::logPrint(const char* fmt, ...) { ++cp; } tid = pid; - logbuf->wrlock(); - uid = logbuf->pidToUid(pid); - logbuf->unlock(); + uid = stats_->PidToUid(pid); memmove(pidptr, cp, strlen(cp) + 1); } @@ -301,9 +298,7 @@ int LogAudit::logPrint(const char* fmt, ...) { pid = tid; comm = "auditd"; } else { - logbuf->wrlock(); - comm = commfree = logbuf->pidToName(pid); - logbuf->unlock(); + comm = commfree = stats_->PidToName(pid); if (!comm) { comm = "unknown"; } diff --git a/logd/LogAudit.h b/logd/LogAudit.h index 7df0a5d8e..ee6e57939 100644 --- a/logd/LogAudit.h +++ b/logd/LogAudit.h @@ -14,14 +14,14 @@ * limitations under the License. */ -#ifndef _LOGD_LOG_AUDIT_H__ -#define _LOGD_LOG_AUDIT_H__ +#pragma once #include #include #include "LogBuffer.h" +#include "LogStatistics.h" class LogReader; @@ -33,14 +33,14 @@ class LogAudit : public SocketListener { bool events; bool initialized; - public: - LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg); + public: + LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg, LogStatistics* stats); int log(char* buf, size_t len); - protected: + protected: virtual bool onDataAvailable(SocketClient* cli); - private: + private: static int getLogSocket(); std::map populateDenialMap(); std::string denialParse(const std::string& denial, char terminator, @@ -48,6 +48,6 @@ class LogAudit : public SocketListener { void auditParse(const std::string& string, uid_t uid, std::string* bug_num); int logPrint(const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); -}; -#endif + LogStatistics* stats_; +}; diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 2cb0c5eba..4fce7512b 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -63,8 +63,8 @@ void LogBuffer::init() { LogReaderThread::unlock(); } -LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune) - : mTimes(*times), tags_(tags), prune_(prune) { +LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats) + : mTimes(*times), tags_(tags), prune_(prune), stats_(stats) { pthread_rwlock_init(&mLogElementsLock, nullptr); log_id_for_each(i) { @@ -197,9 +197,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, } if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) { // Log traffic received to total - wrlock(); - stats.addTotal(elem); - unlock(); + stats_->AddTotal(elem); delete elem; return -EACCES; } @@ -308,7 +306,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, unlock(); return len; } - stats.addTotal(currentLast); + stats_->AddTotal(currentLast); delete currentLast; swab = total; event->payload.data = htole32(swab); @@ -324,7 +322,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, } } if (count) { - stats.addTotal(currentLast); + stats_->AddTotal(currentLast); currentLast->setDropped(count); } droppedElements[log_id] = currentLast; @@ -355,31 +353,15 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, // assumes LogBuffer::wrlock() held, owns elem, look after garbage collection void LogBuffer::log(LogBufferElement* elem) { mLogElements.push_back(elem); - stats.add(elem); + stats_->Add(elem); maybePrune(elem->getLogId()); } -// Prune at most 10% of the log entries or maxPrune, whichever is less. -// // LogBuffer::wrlock() must be held when this function is called. void LogBuffer::maybePrune(log_id_t id) { - size_t sizes = stats.sizes(id); - unsigned long maxSize = log_buffer_size(id); - if (sizes > maxSize) { - size_t sizeOver = sizes - ((maxSize * 9) / 10); - size_t elements = stats.realElements(id); - size_t minElements = elements / 100; - if (minElements < minPrune) { - minElements = minPrune; - } - unsigned long pruneRows = elements * sizeOver / sizes; - if (pruneRows < minElements) { - pruneRows = minElements; - } - if (pruneRows > maxPrune) { - pruneRows = maxPrune; - } - prune(id, pruneRows); + unsigned long prune_rows; + if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) { + prune(id, prune_rows); } } @@ -452,9 +434,9 @@ LogBufferElementCollection::iterator LogBuffer::erase( } #endif if (coalesce) { - stats.erase(element); + stats_->Erase(element); } else { - stats.subtract(element); + stats_->Subtract(element); } delete element; @@ -535,7 +517,7 @@ class LogBufferElementLast { // If the selected reader is blocking our pruning progress, decide on // what kind of mitigation is necessary to unblock the situation. void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) { - if (stats.sizes(id) > (2 * log_buffer_size(id))) { // +100% + if (stats_->Sizes(id) > (2 * log_buffer_size(id))) { // +100% // A misbehaving or slow reader has its connection // dropped if we hit too much memory pressure. android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n", @@ -663,19 +645,14 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { // 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); } } } @@ -824,7 +801,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (leading) { it = erase(it); } else { - stats.drop(element); + stats_->Drop(element); element->setDropped(1); if (last.coalesce(element, 1)) { it = erase(it, true); @@ -957,14 +934,6 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) { return busy; } -// get the used space associated with "id". -unsigned long LogBuffer::getSizeUsed(log_id_t id) { - rdlock(); - size_t retval = stats.sizes(id); - unlock(); - return retval; -} - // set the total space allocated to "id" int LogBuffer::setSize(log_id_t id, unsigned long size) { // Reasonable limits ... @@ -1049,7 +1018,7 @@ uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid unlock(); // range locking in LastLogTimes looks after us - curr = element->flushTo(reader, this, sameTid); + curr = element->flushTo(reader, stats_, sameTid); if (curr == element->FLUSH_ERROR) { return curr; @@ -1061,14 +1030,3 @@ uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid return curr; } - -std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid, - unsigned int logMask) { - wrlock(); - - std::string ret = stats.format(uid, pid, logMask); - - unlock(); - - return ret; -} diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 3c45667b9..3c1ea5a2b 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -38,8 +38,6 @@ class LogBuffer { LogBufferElementCollection mLogElements; pthread_rwlock_t mLogElementsLock; - LogStatistics stats; - // watermark of any worst/chatty uid processing typedef std::unordered_map LogBufferIteratorMap; @@ -58,7 +56,7 @@ class LogBuffer { public: LastLogTimes& mTimes; - LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune); + LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats); ~LogBuffer(); void init(); @@ -75,22 +73,8 @@ class LogBuffer { bool clear(log_id_t id, uid_t uid = AID_ROOT); unsigned long getSize(log_id_t id); int setSize(log_id_t id, unsigned long size); - unsigned long getSizeUsed(log_id_t id); - std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask); - - void enableStatistics() { - stats.enableStatistics(); - } - - // helper must be protected directly or implicitly by wrlock()/unlock() - const char* pidToName(pid_t pid) { - return stats.pidToName(pid); - } - uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); } - const char* uidToName(uid_t uid) { - return stats.uidToName(uid); - } + private: void wrlock() { pthread_rwlock_wrlock(&mLogElementsLock); } @@ -101,10 +85,6 @@ class LogBuffer { pthread_rwlock_unlock(&mLogElementsLock); } - private: - static constexpr size_t minPrune = 4; - static constexpr size_t maxPrune = 256; - void maybePrune(log_id_t id); void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows); @@ -118,6 +98,7 @@ class LogBuffer { LogTags* tags_; PruneList* prune_; + LogStatistics* stats_; // Keeps track of the iterator to the oldest log message of a given log type, as an // optimization when pruning logs. Use GetOldest() to retrieve. diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index 916ed42cc..cc68ba4de 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "LogBufferElement.h" + #include #include #include @@ -26,7 +28,6 @@ #include #include "LogBuffer.h" -#include "LogBufferElement.h" #include "LogCommand.h" #include "LogReader.h" #include "LogUtils.h" @@ -153,7 +154,7 @@ char* android::tidToName(pid_t tid) { } // assumption: mMsg == NULL -size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent, +size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogStatistics* stats, bool lastSame) { static const char tag[] = "chatty"; @@ -163,17 +164,13 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent } static const char format_uid[] = "uid=%u%s%s %s %u line%s"; - parent->wrlock(); - const char* name = parent->uidToName(mUid); - parent->unlock(); + const char* name = stats->UidToName(mUid); const char* commName = android::tidToName(mTid); if (!commName && (mTid != mPid)) { commName = android::tidToName(mPid); } if (!commName) { - parent->wrlock(); - commName = parent->pidToName(mPid); - parent->unlock(); + commName = stats->PidToName(mPid); } if (name && name[0] && commName && (name[0] == commName[0])) { size_t len = strlen(name + 1); @@ -246,7 +243,7 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent return retval; } -uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool lastSame) { +uint64_t LogBufferElement::flushTo(SocketClient* reader, LogStatistics* stats, bool lastSame) { struct logger_entry entry = {}; entry.hdr_size = sizeof(struct logger_entry); @@ -264,7 +261,7 @@ uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool char* buffer = nullptr; if (mDropped) { - entry.len = populateDroppedMessage(buffer, parent, lastSame); + entry.len = populateDroppedMessage(buffer, stats, lastSame); if (!entry.len) return mSequence; iovec[1].iov_base = buffer; } else { diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index 434b7dbd3..8676cf173 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -25,6 +25,7 @@ #include class LogBuffer; +class LogStatistics; #define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve // non-chatty UIDs less than this age in hours @@ -55,10 +56,9 @@ class __attribute__((packed)) LogBufferElement { static atomic_int_fast64_t sequence; // assumption: mDropped == true - size_t populateDroppedMessage(char*& buffer, LogBuffer* parent, - bool lastSame); + size_t populateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame); - public: + public: LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg, uint16_t len); LogBufferElement(const LogBufferElement& elem); @@ -98,5 +98,5 @@ class __attribute__((packed)) LogBufferElement { } static const uint64_t FLUSH_ERROR; - uint64_t flushTo(SocketClient* writer, LogBuffer* parent, bool lastSame); + uint64_t flushTo(SocketClient* writer, LogStatistics* parent, bool lastSame); }; diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index c30807365..bc94b45c8 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "LogKlog.h" + #include #include #include @@ -29,7 +31,6 @@ #include #include "LogBuffer.h" -#include "LogKlog.h" #include "LogReader.h" #define KMSG_PRIORITY(PRI) \ @@ -201,15 +202,16 @@ log_time LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTO ? log_time(log_time::EPOCH) : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC)); -LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, - bool auditd) +LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd, + LogStatistics* stats) : SocketListener(fdRead, false), logbuf(buf), reader(reader), signature(CLOCK_MONOTONIC), initialized(false), enableLogging(true), - auditd(auditd) { + auditd(auditd), + stats_(stats) { static const char klogd_message[] = "%s%s%" PRIu64 "\n"; char buffer[strlen(priority_message) + strlen(klogdStr) + strlen(klogd_message) + 20]; @@ -528,9 +530,7 @@ int LogKlog::log(const char* buf, ssize_t len) { const pid_t tid = pid; uid_t uid = AID_ROOT; if (pid) { - logbuf->wrlock(); - uid = logbuf->pidToUid(pid); - logbuf->unlock(); + uid = stats_->PidToUid(pid); } // Parse (rules at top) to pull out a tag from the incoming kernel message. diff --git a/logd/LogKlog.h b/logd/LogKlog.h index 4c0975155..a7dbe642f 100644 --- a/logd/LogKlog.h +++ b/logd/LogKlog.h @@ -14,12 +14,13 @@ * limitations under the License. */ -#ifndef _LOGD_LOG_KLOG_H__ -#define _LOGD_LOG_KLOG_H__ +#pragma once #include #include +#include "LogStatistics.h" + class LogBuffer; class LogReader; @@ -38,20 +39,19 @@ class LogKlog : public SocketListener { static log_time correction; - public: - LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, - bool auditd); + public: + LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd, + LogStatistics* stats); int log(const char* buf, ssize_t len); - static void convertMonotonicToReal(log_time& real) { - real += correction; - } + static void convertMonotonicToReal(log_time& real) { real += correction; } - protected: - log_time sniffTime(const char*& buf, ssize_t len, bool reverse); - pid_t sniffPid(const char*& buf, ssize_t len); - void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len); - virtual bool onDataAvailable(SocketClient* cli); + protected: + log_time sniffTime(const char*& buf, ssize_t len, bool reverse); + pid_t sniffPid(const char*& buf, ssize_t len); + void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len); + virtual bool onDataAvailable(SocketClient* cli); + + private: + LogStatistics* stats_; }; - -#endif diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 431b7784b..14bcb6395 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "LogStatistics.h" + #include #include #include @@ -27,14 +29,12 @@ #include -#include "LogStatistics.h" - static const uint64_t hourSec = 60 * 60; static const uint64_t monthSec = 31 * 24 * hourSec; -size_t LogStatistics::SizesTotal; +std::atomic LogStatistics::SizesTotal; -LogStatistics::LogStatistics() : enable(false) { +LogStatistics::LogStatistics(bool enable_statistics) : enable(enable_statistics) { log_time now(CLOCK_REALTIME); log_id_for_each(id) { mSizes[id] = 0; @@ -79,7 +79,8 @@ char* pidToName(pid_t pid) { } } -void LogStatistics::addTotal(LogBufferElement* element) { +void LogStatistics::AddTotal(LogBufferElement* element) { + auto lock = std::lock_guard{lock_}; if (element->getDropped()) return; log_id_t log_id = element->getLogId(); @@ -89,7 +90,8 @@ void LogStatistics::addTotal(LogBufferElement* element) { ++mElementsTotal[log_id]; } -void LogStatistics::add(LogBufferElement* element) { +void LogStatistics::Add(LogBufferElement* element) { + auto lock = std::lock_guard{lock_}; log_id_t log_id = element->getLogId(); uint16_t size = element->getMsgLen(); mSizes[log_id] += size; @@ -159,7 +161,8 @@ void LogStatistics::add(LogBufferElement* element) { } } -void LogStatistics::subtract(LogBufferElement* element) { +void LogStatistics::Subtract(LogBufferElement* element) { + auto lock = std::lock_guard{lock_}; log_id_t log_id = element->getLogId(); uint16_t size = element->getMsgLen(); mSizes[log_id] -= size; @@ -204,7 +207,8 @@ void LogStatistics::subtract(LogBufferElement* element) { // Atomically set an entry to drop // entry->setDropped(1) must follow this call, caller should do this explicitly. -void LogStatistics::drop(LogBufferElement* element) { +void LogStatistics::Drop(LogBufferElement* element) { + auto lock = std::lock_guard{lock_}; log_id_t log_id = element->getLogId(); uint16_t size = element->getMsgLen(); mSizes[log_id] -= size; @@ -238,9 +242,13 @@ void LogStatistics::drop(LogBufferElement* element) { tagNameTable.subtract(TagNameKey(element), 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"); @@ -297,6 +305,80 @@ const char* LogStatistics::uidToName(uid_t uid) const { return name; } +template +void LogStatistics::WorstTwoWithThreshold(const LogHashtable& table, size_t threshold, + int* worst, size_t* worst_sizes, + size_t* second_worst_sizes) const { + std::array 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) 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 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(); +} + +// 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,10 +390,10 @@ 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 - @@ -332,12 +414,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 { +std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const REQUIRES(stat.lock_) { uid_t uid = getUid(); 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)) { @@ -347,9 +429,9 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const { it != stat.uidTable[id].end(); ++it) { totalDropped += it->second.getDropped(); } - 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(); @@ -401,12 +483,9 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const { } static const size_t maximum_sorted_entries = 32; - std::unique_ptr sorted = - stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries); + std::array sorted; + stat.pidSystemTable[id].MaxEntries(uid, 0, &sorted); - if (!sorted.get()) { - return output; - } std::string byPid; size_t index; bool hasDropped = false; @@ -440,14 +519,14 @@ 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 { +std::string PidEntry::format(const LogStatistics& stat, log_id_t /* id */) const + REQUIRES(stat.lock_) { uid_t uid = getUid(); pid_t pid = getPid(); 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(getName(), uid, name, size, 12); std::string pruned = ""; size_t dropped = getDropped(); @@ -465,13 +544,13 @@ std::string TidEntry::formatHeader(const std::string& name, std::string("NUM")); } -std::string TidEntry::format(const LogStatistics& stat, - log_id_t /* id */) const { +std::string TidEntry::format(const LogStatistics& stat, log_id_t /* id */) const + REQUIRES(stat.lock_) { uid_t uid = getUid(); std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid); std::string size = android::base::StringPrintf("%zu", getSizes()); - formatTmp(stat, getName(), uid, name, size, 12); + stat.FormatTmp(getName(), uid, name, size, 12); std::string pruned = ""; size_t dropped = getDropped(); @@ -611,8 +690,36 @@ static std::string formatMsec(uint64_t val) { return output; } -std::string LogStatistics::format(uid_t uid, pid_t pid, - unsigned int logMask) const { +template +std::string LogStatistics::FormatTable(const LogHashtable& 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 sorted; + table.MaxEntries(uid, pid, &sorted); + bool header_printed = 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 (!header_printed) { + output += "\n\n"; + output += entry->formatHeader(name, id); + header_printed = true; + } + output += entry->format(*this, id); + } + return output; +} + +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 +749,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 +770,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,7 +856,7 @@ 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; @@ -758,7 +865,7 @@ std::string LogStatistics::format(uid_t uid, pid_t pid, ((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) & -sizeof(uint64_t)) + sizeof(std::list); - size_t szs = sizes(id) + els * overhead; + size_t szs = mSizes[id] + els * overhead; totalSize += szs; output += android::base::StringPrintf("%*s%zu", spaces, "", szs); spaces -= output.length() - oldLength; @@ -779,39 +886,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; @@ -839,12 +945,14 @@ uid_t pidToUid(pid_t pid) { } } -uid_t LogStatistics::pidToUid(pid_t pid) { +uid_t LogStatistics::PidToUid(pid_t pid) { + auto lock = std::lock_guard{lock_}; return pidTable.add(pid)->second.getUid(); } // 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); const char* name = writablePidTable.add(pid)->second.getName(); diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index 0782de3d1..53c9bb667 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 #include @@ -25,12 +24,15 @@ #include #include // std::max +#include #include +#include #include #include #include #include +#include #include #include #include @@ -79,16 +81,12 @@ class LogHashtable { typedef typename std::unordered_map::const_iterator const_iterator; - std::unique_ptr sort(uid_t uid, pid_t pid, - size_t len) const { - if (!len) { - std::unique_ptr 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 + void MaxEntries(uid_t uid, pid_t pid, std::array* 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 +111,6 @@ class LogHashtable { retval[index] = &entry; } } - std::unique_ptr sorted(retval); - return sorted; } inline iterator add(const TKey& key, const LogBufferElement* element) { @@ -170,35 +166,6 @@ class LogHashtable { inline const_iterator end() const { return map.end(); } - - std::string format(const LogStatistics& stat, uid_t uid, pid_t pid, - 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 sorted = - sort(uid, pid, 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 (!headerPrinted) { - output += "\n\n"; - output += entry->formatHeader(name, id); - headerPrinted = true; - } - output += entry->format(stat, id); - } - return output; - } }; namespace EntryBaseConstants { @@ -627,84 +594,51 @@ struct TagNameEntry : public EntryBase { std::string format(const LogStatistics& stat, log_id_t id) const; }; -template -class LogFindWorst { - std::unique_ptr sorted; - - public: - explicit LogFindWorst(std::unique_ptr&& 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; + friend PidEntry; + friend TidEntry; - size_t mSizes[LOG_ID_MAX]; - size_t mElements[LOG_ID_MAX]; - size_t mDroppedElements[LOG_ID_MAX]; - size_t mSizesTotal[LOG_ID_MAX]; - size_t mElementsTotal[LOG_ID_MAX]; - log_time mOldest[LOG_ID_MAX]; - log_time mNewest[LOG_ID_MAX]; - log_time mNewestDropped[LOG_ID_MAX]; - static size_t SizesTotal; + size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_); + size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_); + size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_); + size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_); + size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_); + log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_); + log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_); + log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_); + static std::atomic SizesTotal; bool enable; // uid to size list typedef LogHashtable uidTable_t; - uidTable_t uidTable[LOG_ID_MAX]; + uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_); // pid of system to size list typedef LogHashtable pidSystemTable_t; - pidSystemTable_t pidSystemTable[LOG_ID_MAX]; + pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_); // pid to uid list typedef LogHashtable pidTable_t; - pidTable_t pidTable; + pidTable_t pidTable GUARDED_BY(lock_); // tid to uid list typedef LogHashtable tidTable_t; - tidTable_t tidTable; + tidTable_t tidTable GUARDED_BY(lock_); // tag list typedef LogHashtable tagTable_t; - tagTable_t tagTable; + tagTable_t tagTable GUARDED_BY(lock_); // security tag list - tagTable_t securityTagTable; + tagTable_t securityTagTable GUARDED_BY(lock_); // global tag list typedef LogHashtable tagNameTable_t; tagNameTable_t tagNameTable; - size_t sizeOf() const { + size_t sizeOf() const REQUIRES(lock_) { size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() + tagTable.sizeOf() + securityTagTable.sizeOf() + tagNameTable.sizeOf() + @@ -729,62 +663,59 @@ class LogStatistics { return size; } - public: - LogStatistics(); + public: + LogStatistics(bool enable_statistics); - void enableStatistics() { - enable = true; - } - - void addTotal(LogBufferElement* entry); - void add(LogBufferElement* entry); - void subtract(LogBufferElement* entry); + void AddTotal(LogBufferElement* entry) EXCLUDES(lock_); + void Add(LogBufferElement* entry) EXCLUDES(lock_); + void Subtract(LogBufferElement* entry) EXCLUDES(lock_); // entry->setDropped(1) must follow this call - void drop(LogBufferElement* entry); + void Drop(LogBufferElement* entry) EXCLUDES(lock_); // Correct for coalescing two entries referencing dropped content - void erase(LogBufferElement* element) { + void Erase(LogBufferElement* element) EXCLUDES(lock_) { + auto lock = std::lock_guard{lock_}; log_id_t log_id = element->getLogId(); --mElements[log_id]; --mDroppedElements[log_id]; } - LogFindWorst sort(uid_t uid, pid_t pid, size_t len, log_id id) { - return LogFindWorst(uidTable[id].sort(uid, pid, len)); - } - LogFindWorst sortPids(uid_t uid, pid_t pid, size_t len, - log_id id) { - return LogFindWorst(pidSystemTable[id].sort(uid, pid, len)); - } - LogFindWorst sortTags(uid_t uid, pid_t pid, size_t len, log_id) { - return LogFindWorst(tagTable.sort(uid, pid, len)); - } + void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes, + size_t* second_worst_sizes) const EXCLUDES(lock_); + void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes, + size_t* second_worst_sizes) const EXCLUDES(lock_); + void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst, + size_t* second_worst_sizes) const EXCLUDES(lock_); - // fast track current value by id only - size_t sizes(log_id_t id) const { + bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const + EXCLUDES(lock_); + + // Snapshot of the sizes for a given log buffer. + size_t Sizes(log_id_t id) const EXCLUDES(lock_) { + auto lock = std::lock_guard{lock_}; return mSizes[id]; } - size_t elements(log_id_t id) const { - return mElements[id]; - } - size_t realElements(log_id_t id) const { - return mElements[id] - mDroppedElements[id]; - } - size_t sizesTotal(log_id_t id) const { - return mSizesTotal[id]; - } - size_t elementsTotal(log_id_t id) const { - return mElementsTotal[id]; - } + // TODO: Get rid of this entirely. static size_t sizesTotal() { return SizesTotal; } - std::string format(uid_t uid, pid_t pid, unsigned int logMask) const; + std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_); - // helper (must be locked directly or implicitly by mLogElementsLock) - const char* pidToName(pid_t pid) const; - uid_t pidToUid(pid_t pid); - const char* uidToName(uid_t uid) const; + const char* PidToName(pid_t pid) const EXCLUDES(lock_); + uid_t PidToUid(pid_t pid) EXCLUDES(lock_); + const char* UidToName(uid_t uid) const EXCLUDES(lock_); + + private: + template + void WorstTwoWithThreshold(const LogHashtable& table, size_t threshold, + int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const; + template + std::string FormatTable(const LogHashtable& table, uid_t uid, pid_t pid, + const std::string& name = std::string(""), + log_id_t id = LOG_ID_MAX) const REQUIRES(lock_); + void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size, + size_t nameLen) const REQUIRES(lock_); + const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_); + + mutable std::mutex lock_; }; - -#endif // _LOGD_LOG_STATISTICS_H__ diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp index 082e4a1e6..8250808b5 100644 --- a/logd/LogTags.cpp +++ b/logd/LogTags.cpp @@ -37,6 +37,7 @@ #include #include +#include "LogStatistics.h" #include "LogTags.h" #include "LogUtils.h" @@ -493,7 +494,7 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) { // Every 16K (half the smallest configurable pmsg buffer size) record static const size_t rate_to_pmsg = 16 * 1024; - if (lastTotal && ((android::sizesTotal() - lastTotal) < rate_to_pmsg)) { + if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) { return; } @@ -663,7 +664,7 @@ void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid, } } - lastTotal = android::sizesTotal(); + lastTotal = LogStatistics::sizesTotal(); if (!lastTotal) ++lastTotal; // record totals for next watermark. diff --git a/logd/LogUtils.h b/logd/LogUtils.h index f9cd42dcb..3fe1bbeff 100644 --- a/logd/LogUtils.h +++ b/logd/LogUtils.h @@ -32,8 +32,6 @@ namespace android { char* uidToName(uid_t uid); void prdebug(const char* fmt, ...) __printflike(1, 2); -// Furnished in LogStatistics.cpp. -size_t sizesTotal(); // Caller must own and free returned value char* pidToName(pid_t pid); char* tidToName(pid_t tid); diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp index 8156612da..58610c490 100644 --- a/logd/fuzz/log_buffer_log_fuzzer.cpp +++ b/logd/fuzz/log_buffer_log_fuzzer.cpp @@ -17,6 +17,7 @@ #include "../LogBuffer.h" #include "../LogReaderThread.h" +#include "../LogStatistics.h" // We don't want to waste a lot of entropy on messages #define MAX_MSG_LENGTH 5 @@ -36,7 +37,8 @@ struct LogInput { unsigned int log_mask; }; -int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer) { +int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer, + LogStatistics* stats) { const uint8_t* data = *pdata; const LogInput* logInput = reinterpret_cast(data); data += sizeof(LogInput); @@ -71,7 +73,7 @@ int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_ log_id_t log_id = static_cast(unsigned(logInput->log_id) % (LOG_ID_MAX + 1)); log_buffer->log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg, sizeof(uint32_t) + msg_length + 1); - log_buffer->formatStatistics(logInput->uid, logInput->pid, logInput->log_mask); + stats->Format(logInput->uid, logInput->pid, logInput->log_mask); *pdata = data; return 1; } @@ -96,17 +98,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { LastLogTimes times; LogTags tags; PruneList prune_list; - LogBuffer log_buffer(×, &tags, &prune_list); + LogStatistics stats(true); + LogBuffer log_buffer(×, &tags, &prune_list, &stats); size_t data_left = size; const uint8_t** pdata = &data; - log_buffer.enableStatistics(); prune_list.init(nullptr); // We want to get pruning code to get called. log_id_for_each(i) { log_buffer.setSize(i, 10000); } while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) { - if (!write_log_messages(pdata, &data_left, &log_buffer)) { + if (!write_log_messages(pdata, &data_left, &log_buffer, &stats)) { return 0; } } diff --git a/logd/main.cpp b/logd/main.cpp index ceddd0f85..cd8b19597 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -52,6 +52,7 @@ #include "LogBuffer.h" #include "LogKlog.h" #include "LogListener.h" +#include "LogStatistics.h" #include "LogTags.h" #include "LogUtils.h" @@ -272,6 +273,11 @@ int main(int argc, char* argv[]) { LogTags log_tags; // Pruning configuration. PruneList prune_list; + // Partial (required for chatty) or full logging statistics. + bool enable_full_log_statistics = __android_logger_property_get_bool( + "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST | + BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); + LogStatistics log_statistics(enable_full_log_statistics); // Serves the purpose of managing the last logs times read on a // socket connection, and as a reader lock on a range of log @@ -282,14 +288,7 @@ int main(int argc, char* argv[]) { // LogBuffer is the object which is responsible for holding all // log entries. - LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list); - - if (__android_logger_property_get_bool( - "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST | - BOOL_DEFAULT_FLAG_ENG | - BOOL_DEFAULT_FLAG_SVELTE)) { - logBuf->enableStatistics(); - } + LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list, &log_statistics); // LogReader listens on /dev/socket/logdr. When a client // connects, log entries in the LogBuffer are written to the client. @@ -311,7 +310,7 @@ int main(int argc, char* argv[]) { // Command listener listens on /dev/socket/logd for incoming logd // administrative commands. - CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list); + CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list, &log_statistics); if (cl->startListener()) { return EXIT_FAILURE; } @@ -322,16 +321,17 @@ int main(int argc, char* argv[]) { LogAudit* al = nullptr; if (auditd) { - al = new LogAudit(logBuf, reader, - __android_logger_property_get_bool( - "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE) - ? fdDmesg - : -1); + al = new LogAudit( + logBuf, reader, + __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE) + ? fdDmesg + : -1, + &log_statistics); } LogKlog* kl = nullptr; if (klogd) { - kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr); + kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr, &log_statistics); } readDmesg(al, kl);