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