summaryrefslogtreecommitdiffstats
path: root/logd/LogBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'logd/LogBuffer.cpp')
-rw-r--r--logd/LogBuffer.cpp217
1 files changed, 196 insertions, 21 deletions
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index c5760f7..197b7e8 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -22,18 +22,26 @@
#include <log/logger.h>
#include "LogBuffer.h"
+#include "LogStatistics.h"
+#include "LogWhiteBlackList.h"
#include "LogReader.h"
+// Default
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
+#ifdef USERDEBUG_BUILD
+#define log_buffer_size(id) mMaxSize[id]
+#else
+#define log_buffer_size(id) LOG_BUFFER_SIZE
+#endif
LogBuffer::LogBuffer(LastLogTimes *times)
: mTimes(*times) {
- int i;
- for (i = 0; i < LOG_ID_MAX; i++) {
- mSizes[i] = 0;
- mElements[i] = 0;
- }
pthread_mutex_init(&mLogElementsLock, NULL);
+#ifdef USERDEBUG_BUILD
+ log_id_for_each(i) {
+ mMaxSize[i] = LOG_BUFFER_SIZE;
+ }
+#endif
}
void LogBuffer::log(log_id_t log_id, log_time realtime,
@@ -93,8 +101,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
LogTimeEntry::unlock();
}
- mSizes[log_id] += len;
- mElements[log_id]++;
+ stats.add(len, log_id, uid, pid);
maybePrune(log_id);
pthread_mutex_unlock(&mLogElementsLock);
}
@@ -104,10 +111,10 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
//
// mLogElementsLock must be held when this function is called.
void LogBuffer::maybePrune(log_id_t id) {
- unsigned long sizes = mSizes[id];
- if (sizes > LOG_BUFFER_SIZE) {
- unsigned long sizeOver90Percent = sizes - ((LOG_BUFFER_SIZE * 9) / 10);
- unsigned long elements = mElements[id];
+ size_t sizes = stats.sizes(id);
+ if (sizes > log_buffer_size(id)) {
+ size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
+ size_t elements = stats.elements(id);
unsigned long pruneRows = elements * sizeOver90Percent / sizes;
elements /= 10;
if (pruneRows <= elements) {
@@ -136,22 +143,117 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
t++;
}
- LogBufferElementCollection::iterator it = mLogElements.begin();
+ LogBufferElementCollection::iterator it;
+
+ // prune by worst offender by uid
+ while (pruneRows > 0) {
+ // recalculate the worst offender on every batched pass
+ uid_t worst = (uid_t) -1;
+ size_t worst_sizes = 0;
+ size_t second_worst_sizes = 0;
+
+#ifdef USERDEBUG_BUILD
+ if (mPrune.worstUidEnabled())
+#endif
+ {
+ LidStatistics &l = stats.id(id);
+ UidStatisticsCollection::iterator iu;
+ for (iu = l.begin(); iu != l.end(); ++iu) {
+ UidStatistics *u = (*iu);
+ size_t sizes = u->sizes();
+ if (worst_sizes < sizes) {
+ second_worst_sizes = worst_sizes;
+ worst_sizes = sizes;
+ worst = u->getUid();
+ }
+ if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
+ second_worst_sizes = sizes;
+ }
+ }
+ }
+
+ bool kick = false;
+ for(it = mLogElements.begin(); it != mLogElements.end();) {
+ LogBufferElement *e = *it;
+
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ break;
+ }
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
+ }
+
+ uid_t uid = e->getUid();
+
+ if (uid == worst) {
+ it = mLogElements.erase(it);
+ unsigned short len = e->getMsgLen();
+ stats.subtract(len, id, worst, e->getPid());
+ delete e;
+ kick = true;
+ pruneRows--;
+ if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
+ break;
+ }
+ worst_sizes -= len;
+ }
+#ifdef USERDEBUG_BUILD
+ else if (mPrune.naughty(e)) { // BlackListed
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+ delete e;
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+ }
+#endif
+ else {
+ ++it;
+ }
+ }
+
+ if (!kick
+#ifdef USERDEBUG_BUILD
+ || !mPrune.worstUidEnabled()
+#endif
+ ) {
+ break; // the following loop will ask bad clients to skip/drop
+ }
+ }
+
+#ifdef USERDEBUG_BUILD
+ bool whitelist = false;
+#endif
+ it = mLogElements.begin();
while((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement *e = *it;
if (e->getLogId() == id) {
if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
- if (mSizes[id] > (2 * LOG_BUFFER_SIZE)) {
- // kick a misbehaving log reader client off the island
- oldest->release_Locked();
- } else {
- oldest->triggerSkip_Locked(pruneRows);
+#ifdef USERDEBUG_BUILD
+ if (!whitelist)
+#endif
+ {
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(pruneRows);
+ }
}
break;
}
+#ifdef USERDEBUG_BUILD
+ if (mPrune.nice(e)) { // WhiteListed
+ whitelist = true;
+ it++;
+ continue;
+ }
+#endif
it = mLogElements.erase(it);
- mSizes[id] -= e->getMsgLen();
- mElements[id]--;
+ stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
delete e;
pruneRows--;
} else {
@@ -159,6 +261,32 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
}
}
+#ifdef USERDEBUG_BUILD
+ if (whitelist && (pruneRows > 0)) {
+ it = mLogElements.begin();
+ while((it != mLogElements.end()) && (pruneRows > 0)) {
+ LogBufferElement *e = *it;
+ if (e->getLogId() == id) {
+ if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(pruneRows);
+ }
+ break;
+ }
+ it = mLogElements.erase(it);
+ stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
+ delete e;
+ pruneRows--;
+ } else {
+ it++;
+ }
+ }
+ }
+#endif
+
LogTimeEntry::unlock();
}
@@ -172,16 +300,42 @@ void LogBuffer::clear(log_id_t id) {
// get the used space associated with "id".
unsigned long LogBuffer::getSizeUsed(log_id_t id) {
pthread_mutex_lock(&mLogElementsLock);
- unsigned long retval = mSizes[id];
+ size_t retval = stats.sizes(id);
+ pthread_mutex_unlock(&mLogElementsLock);
+ return retval;
+}
+
+#ifdef USERDEBUG_BUILD
+
+// set the total space allocated to "id"
+int LogBuffer::setSize(log_id_t id, unsigned long size) {
+ // Reasonable limits ...
+ if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
+ return -1;
+ }
+ pthread_mutex_lock(&mLogElementsLock);
+ log_buffer_size(id) = size;
+ pthread_mutex_unlock(&mLogElementsLock);
+ return 0;
+}
+
+// get the total space allocated to "id"
+unsigned long LogBuffer::getSize(log_id_t id) {
+ pthread_mutex_lock(&mLogElementsLock);
+ size_t retval = log_buffer_size(id);
pthread_mutex_unlock(&mLogElementsLock);
return retval;
}
+#else // ! USERDEBUG_BUILD
+
// get the total space allocated to "id"
unsigned long LogBuffer::getSize(log_id_t /*id*/) {
- return LOG_BUFFER_SIZE;
+ return log_buffer_size(id);
}
+#endif
+
log_time LogBuffer::flushTo(
SocketClient *reader, const log_time start, bool privileged,
bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
@@ -221,3 +375,24 @@ log_time LogBuffer::flushTo(
return max;
}
+
+void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
+ log_time oldest(CLOCK_MONOTONIC);
+
+ pthread_mutex_lock(&mLogElementsLock);
+
+ // Find oldest element in the log(s)
+ LogBufferElementCollection::iterator it;
+ for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
+ LogBufferElement *element = *it;
+
+ if ((logMask & (1 << element->getLogId()))) {
+ oldest = element->getMonotonicTime();
+ break;
+ }
+ }
+
+ stats.format(strp, uid, logMask, oldest);
+
+ pthread_mutex_unlock(&mLogElementsLock);
+}