logd: separate LogStatistics from LogBuffer
LogStatistics is intertwined with LogBuffer, even relying on it for
thread safety. This needs to change to have a proper
LogBufferInterface, so this CL separates them. Specifically:
1) Adding a lock to LogStatistics and adding thread annotations to
ensure that data structures are protected appropriately.
2) Moving prune_rows calculation into LogStatistics so it is done
while holding this lock.
3) Using LogStatistics instead of LogBuffer where appropriate.
Note that there should not be a significant performance regression
with this lock, as it will almost always been uncontended. If
anything, it should alleviate pressure from LogBuffer's lock.
Test: logging unit tests
Change-Id: I9d6dde2c96c9f024fa0341711c7bc63379e8e406
diff --git a/logd/Android.bp b/logd/Android.bp
index ea1054d..3df59f5 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -54,6 +54,7 @@
cflags: [
"-Wextra",
+ "-Wthread-safety",
] + event_flag,
}
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 4044dc9..87402ac 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "CommandListener.h"
+
#include <arpa/inet.h>
#include <ctype.h>
#include <dirent.h>
@@ -35,12 +37,11 @@
#include <private/android_filesystem_config.h>
#include <sysutils/SocketClient.h>
-#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 @@
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 @@
}
}
- 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 c90c247..fd934f7 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 @@
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 bcc187d..6c42a28 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogAudit.h"
+
#include <ctype.h>
#include <endian.h>
#include <errno.h>
@@ -34,8 +36,6 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#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 @@
++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 @@
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 7df0a5d..ee6e579 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 <map>
#include <sysutils/SocketListener.h>
#include "LogBuffer.h"
+#include "LogStatistics.h"
class LogReader;
@@ -33,14 +33,14 @@
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<std::string, std::string> populateDenialMap();
std::string denialParse(const std::string& denial, char terminator,
@@ -48,6 +48,6 @@
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 ad391e5..4fce751 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -63,8 +63,8 @@
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 @@
}
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 @@
unlock();
return len;
}
- stats.addTotal(currentLast);
+ stats_->AddTotal(currentLast);
delete currentLast;
swab = total;
event->payload.data = htole32(swab);
@@ -324,7 +322,7 @@
}
}
if (count) {
- stats.addTotal(currentLast);
+ stats_->AddTotal(currentLast);
currentLast->setDropped(count);
}
droppedElements[log_id] = currentLast;
@@ -355,31 +353,15 @@
// 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 @@
}
#endif
if (coalesce) {
- stats.erase(element);
+ stats_->Erase(element);
} else {
- stats.subtract(element);
+ stats_->Subtract(element);
}
delete element;
@@ -535,7 +517,7 @@
// 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",
@@ -664,13 +646,13 @@
size_t threshold = log_buffer_size(id) / 8;
if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
- stats.WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
+ stats_->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
// per-pid filter for AID_SYSTEM sources is too complex
} else {
- stats.WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
+ stats_->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
- stats.WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
+ stats_->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
}
}
}
@@ -819,7 +801,7 @@
if (leading) {
it = erase(it);
} else {
- stats.drop(element);
+ stats_->Drop(element);
element->setDropped(1);
if (last.coalesce(element, 1)) {
it = erase(it, true);
@@ -952,14 +934,6 @@
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 ...
@@ -1044,7 +1018,7 @@
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;
@@ -1056,14 +1030,3 @@
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 3c45667..3c1ea5a 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -38,8 +38,6 @@
LogBufferElementCollection mLogElements;
pthread_rwlock_t mLogElementsLock;
- LogStatistics stats;
-
// watermark of any worst/chatty uid processing
typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
LogBufferIteratorMap;
@@ -58,7 +56,7 @@
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 @@
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 @@
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 @@
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 916ed42..cc68ba4 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogBufferElement.h"
+
#include <ctype.h>
#include <endian.h>
#include <fcntl.h>
@@ -26,7 +28,6 @@
#include <private/android_logger.h>
#include "LogBuffer.h"
-#include "LogBufferElement.h"
#include "LogCommand.h"
#include "LogReader.h"
#include "LogUtils.h"
@@ -153,7 +154,7 @@
}
// 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 @@
}
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 @@
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 @@
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 434b7db..8676cf1 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -25,6 +25,7 @@
#include <sysutils/SocketClient.h>
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 @@
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 @@
}
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 c308073..bc94b45 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "LogKlog.h"
+
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
@@ -29,7 +31,6 @@
#include <private/android_logger.h>
#include "LogBuffer.h"
-#include "LogKlog.h"
#include "LogReader.h"
#define KMSG_PRIORITY(PRI) \
@@ -201,15 +202,16 @@
? 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 @@
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 4c09751..a7dbe64 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 <private/android_logger.h>
#include <sysutils/SocketListener.h>
+#include "LogStatistics.h"
+
class LogBuffer;
class LogReader;
@@ -38,20 +39,19 @@
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 4c4c1db..14bcb63 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>
@@ -27,14 +29,12 @@
#include <private/android_logger.h>
-#include "LogStatistics.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;
-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 @@
}
}
-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 @@
++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::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 @@
// 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 @@
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");
@@ -300,7 +308,7 @@
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) {
+ size_t* second_worst_sizes) const {
std::array<const TEntry*, 2> max_entries;
table.MaxEntries(AID_ROOT, 0, &max_entries);
if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
@@ -319,17 +327,20 @@
}
void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_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) {
+ 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) {
+ size_t* second_worst_sizes) const {
+ auto lock = std::lock_guard{lock_};
std::array<const PidEntry*, 2> max_entries;
pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
@@ -340,6 +351,34 @@
*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(),
@@ -351,10 +390,10 @@
}
// 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 -
@@ -375,12 +414,12 @@
}
}
-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)) {
@@ -390,9 +429,9 @@
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();
@@ -480,14 +519,14 @@
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();
@@ -505,13 +544,13 @@
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();
@@ -651,8 +690,36 @@
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 TEntry*, maximum_sorted_entries> 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
@@ -682,9 +749,9 @@
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);
@@ -703,11 +770,11 @@
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 +=
@@ -789,7 +856,7 @@
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;
@@ -798,7 +865,7 @@
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
-sizeof(uint64_t)) +
sizeof(std::list<LogBufferElement*>);
- 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;
@@ -819,39 +886,38 @@
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;
@@ -879,12 +945,14 @@
}
}
-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_t&>(pidTable);
const char* name = writablePidTable.add(pid)->second.getName();
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index ed9002a..53c9bb6 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -26,11 +26,13 @@
#include <algorithm> // std::max
#include <array>
#include <memory>
+#include <mutex>
#include <string>
#include <string_view>
#include <unordered_map>
#include <android-base/stringprintf.h>
+#include <android-base/thread_annotations.h>
#include <android/log.h>
#include <log/log_time.h>
#include <private/android_filesystem_config.h>
@@ -164,32 +166,6 @@
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::array<const TEntry*, maximum_sorted_entries> sorted;
- MaxEntries(uid, pid, &sorted);
- bool headerPrinted = false;
- for (size_t index = 0; index < maximum_sorted_entries; ++index) {
- const TEntry* entry = sorted[index];
- 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 {
@@ -621,46 +597,48 @@
// 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<size_t> SizesTotal;
bool enable;
// uid to size list
typedef LogHashtable<uid_t, UidEntry> 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<pid_t, PidEntry> pidSystemTable_t;
- pidSystemTable_t pidSystemTable[LOG_ID_MAX];
+ pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
// pid to uid list
typedef LogHashtable<pid_t, PidEntry> pidTable_t;
- pidTable_t pidTable;
+ pidTable_t pidTable GUARDED_BY(lock_);
// tid to uid list
typedef LogHashtable<pid_t, TidEntry> tidTable_t;
- tidTable_t tidTable;
+ tidTable_t tidTable GUARDED_BY(lock_);
// tag list
typedef LogHashtable<uint32_t, TagEntry> 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<TagNameKey, TagNameEntry> 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() +
@@ -685,61 +663,59 @@
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];
}
void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_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);
+ 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);
+ 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 <typename TKey, typename TEntry>
void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
- int* worst, size_t* worst_sizes, size_t* second_worst_sizes);
+ int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
+ template <typename TKey, typename TEntry>
+ std::string FormatTable(const LogHashtable<TKey, TEntry>& 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_;
};
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
index 082e4a1..8250808 100644
--- a/logd/LogTags.cpp
+++ b/logd/LogTags.cpp
@@ -37,6 +37,7 @@
#include <log/log_read.h>
#include <private/android_filesystem_config.h>
+#include "LogStatistics.h"
#include "LogTags.h"
#include "LogUtils.h"
@@ -493,7 +494,7 @@
// 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 @@
}
}
- 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 f9cd42d..3fe1bbe 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -32,8 +32,6 @@
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 8156612..58610c4 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 @@
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<const LogInput*>(data);
data += sizeof(LogInput);
@@ -71,7 +73,7 @@
log_id_t log_id = static_cast<log_id_t>(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 @@
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 d9dd249..d1e05b9 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 @@
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 @@
// 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.
@@ -312,7 +311,7 @@
// 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;
}
@@ -323,16 +322,17 @@
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);