diff --git a/logd/Android.bp b/logd/Android.bp index 4f1b2b296..80e3cb2c9 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -33,12 +33,12 @@ cc_library_static { srcs: [ "LogCommand.cpp", + "ChattyLogBuffer.cpp", "CommandListener.cpp", "LogListener.cpp", "LogReader.cpp", "LogReaderList.cpp", "LogReaderThread.cpp", - "LogBuffer.cpp", "LogBufferElement.cpp", "LogStatistics.cpp", "LogWhiteBlackList.cpp", diff --git a/logd/LogBuffer.cpp b/logd/ChattyLogBuffer.cpp similarity index 86% rename from logd/LogBuffer.cpp rename to logd/ChattyLogBuffer.cpp index bb54a5a16..fa5bceef0 100644 --- a/logd/LogBuffer.cpp +++ b/logd/ChattyLogBuffer.cpp @@ -13,9 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -// for manual checking of stale entries during LogBuffer::erase() +// for manual checking of stale entries during ChattyLogBuffer::erase() //#define DEBUG_CHECK_FOR_STALE_ENTRIES +#include "ChattyLogBuffer.h" + #include #include #include @@ -32,7 +34,6 @@ #include #include -#include "LogBuffer.h" #include "LogKlog.h" #include "LogReader.h" #include "LogUtils.h" @@ -44,10 +45,10 @@ // Default #define log_buffer_size(id) mMaxSize[id] -void LogBuffer::init() { +void ChattyLogBuffer::Init() { log_id_for_each(i) { - if (setSize(i, __android_logger_get_buffer_size(i))) { - setSize(i, LOG_BUFFER_MIN_SIZE); + if (SetSize(i, __android_logger_get_buffer_size(i))) { + SetSize(i, LOG_BUFFER_MIN_SIZE); } } // Release any sleeping reader threads to dump their current content. @@ -57,8 +58,8 @@ void LogBuffer::init() { } } -LogBuffer::LogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, - LogStatistics* stats) +ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, + LogStatistics* stats) : reader_list_(reader_list), tags_(tags), prune_(prune), stats_(stats) { pthread_rwlock_init(&mLogElementsLock, nullptr); @@ -67,17 +68,17 @@ LogBuffer::LogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune droppedElements[i] = nullptr; } - init(); + Init(); } -LogBuffer::~LogBuffer() { +ChattyLogBuffer::~ChattyLogBuffer() { log_id_for_each(i) { delete lastLoggedElements[i]; delete droppedElements[i]; } } -LogBufferElementCollection::iterator LogBuffer::GetOldest(log_id_t log_id) { +LogBufferElementCollection::iterator ChattyLogBuffer::GetOldest(log_id_t log_id) { auto it = mLogElements.begin(); if (oldest_[log_id]) { it = *oldest_[log_id]; @@ -93,8 +94,7 @@ LogBufferElementCollection::iterator LogBuffer::GetOldest(log_id_t log_id) { enum match_type { DIFFERENT, SAME, SAME_LIBLOG }; -static enum match_type identical(LogBufferElement* elem, - LogBufferElement* last) { +static enum match_type identical(LogBufferElement* elem, LogBufferElement* last) { // is it mostly identical? // if (!elem) return DIFFERENT; ssize_t lenl = elem->getMsgLen(); @@ -108,8 +108,7 @@ static enum match_type identical(LogBufferElement* elem, if (elem->getTid() != last->getTid()) return DIFFERENT; // last is more than a minute old, stop squashing identical messages - if (elem->getRealTime().nsec() > - (last->getRealTime().nsec() + 60 * NS_PER_SEC)) + if (elem->getRealTime().nsec() > (last->getRealTime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT; // Identical message @@ -118,21 +117,17 @@ static enum match_type identical(LogBufferElement* elem, if (lenl == lenr) { if (!fastcmp(msgl, msgr, lenl)) return SAME; // liblog tagged messages (content gets summed) - if ((elem->getLogId() == LOG_ID_EVENTS) && - (lenl == sizeof(android_log_event_int_t)) && - !fastcmp(msgl, msgr, sizeof(android_log_event_int_t) - - sizeof(int32_t)) && - (elem->getTag() == LIBLOG_LOG_TAG)) { + if (elem->getLogId() == LOG_ID_EVENTS && lenl == sizeof(android_log_event_int_t) && + !fastcmp(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) && + elem->getTag() == LIBLOG_LOG_TAG) { return SAME_LIBLOG; } } // audit message (except sequence number) identical? - if (last->isBinary() && - (lenl > static_cast(sizeof(android_log_event_string_t))) && - (lenr > static_cast(sizeof(android_log_event_string_t)))) { - if (fastcmp(msgl, msgr, sizeof(android_log_event_string_t) - - sizeof(int32_t))) { + if (last->isBinary() && lenl > static_cast(sizeof(android_log_event_string_t)) && + lenr > static_cast(sizeof(android_log_event_string_t))) { + if (fastcmp(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) { return DIFFERENT; } msgl += sizeof(android_log_event_string_t); @@ -148,15 +143,14 @@ static enum match_type identical(LogBufferElement* elem, if (!avcr) return DIFFERENT; lenr -= avcr - msgr; if (lenl != lenr) return DIFFERENT; - if (fastcmp(avcl + strlen(avc), avcr + strlen(avc), - lenl - strlen(avc))) { + if (fastcmp(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) { return DIFFERENT; } return SAME; } -int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, - pid_t tid, const char* msg, uint16_t len) { +int ChattyLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len) { if (log_id >= LOG_ID_MAX) { return -EINVAL; } @@ -278,8 +272,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, if (dropped) { // Sum up liblog tag messages? if ((count == 0) /* at Pass 1 */ && (match == SAME_LIBLOG)) { - android_log_event_int_t* event = - reinterpret_cast( + android_log_event_int_t* event = reinterpret_cast( const_cast(currentLast->getMsg())); // // To unit test, differentiate with something like: @@ -290,7 +283,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, uint32_t swab = event->payload.data; unsigned long long total = htole32(swab); event = reinterpret_cast( - const_cast(elem->getMsg())); + const_cast(elem->getMsg())); swab = event->payload.data; lastLoggedElements[LOG_ID_EVENTS] = elem; @@ -345,24 +338,24 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, return len; } -// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection -void LogBuffer::log(LogBufferElement* elem) { +// assumes ChattyLogBuffer::wrlock() held, owns elem, look after garbage collection +void ChattyLogBuffer::log(LogBufferElement* elem) { mLogElements.push_back(elem); stats_->Add(elem); maybePrune(elem->getLogId()); reader_list_->NotifyNewLog(1 << elem->getLogId()); } -// LogBuffer::wrlock() must be held when this function is called. -void LogBuffer::maybePrune(log_id_t id) { +// ChattyLogBuffer::wrlock() must be held when this function is called. +void ChattyLogBuffer::maybePrune(log_id_t id) { unsigned long prune_rows; if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) { prune(id, prune_rows); } } -LogBufferElementCollection::iterator LogBuffer::erase( - LogBufferElementCollection::iterator it, bool coalesce) { +LogBufferElementCollection::iterator ChattyLogBuffer::erase(LogBufferElementCollection::iterator it, + bool coalesce) { LogBufferElement* element = *it; log_id_t id = element->getLogId(); @@ -370,9 +363,8 @@ LogBufferElementCollection::iterator LogBuffer::erase( // after the element is erased from the main logging list. { // start of scope for found iterator - int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) - ? element->getTag() - : element->getUid(); + int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() + : element->getUid(); LogBufferIteratorMap::iterator found = mLastWorst[id].find(key); if ((found != mLastWorst[id].end()) && (it == found->second)) { mLastWorst[id].erase(found); @@ -383,10 +375,8 @@ LogBufferElementCollection::iterator LogBuffer::erase( // element->getUid() may not be AID_SYSTEM for next-best-watermark. // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and // long term code stability, find() check should be fast for those ids. - LogBufferPidIteratorMap::iterator found = - mLastWorstPidOfSystem[id].find(element->getPid()); - if ((found != mLastWorstPidOfSystem[id].end()) && - (it == found->second)) { + LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element->getPid()); + if (found != mLastWorstPidOfSystem[id].end() && it == found->second) { mLastWorstPidOfSystem[id].erase(found); } } @@ -396,9 +386,8 @@ LogBufferElementCollection::iterator LogBuffer::erase( log_id_for_each(i) { doSetLast |= setLast[i] = oldest_[i] && it == *oldest_[i]; } #ifdef DEBUG_CHECK_FOR_STALE_ENTRIES LogBufferElementCollection::iterator bad = it; - int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) - ? element->getTag() - : element->getUid(); + int key = + (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() : element->getUid(); #endif it = mLogElements.erase(it); if (doSetLast) { @@ -417,14 +406,12 @@ LogBufferElementCollection::iterator LogBuffer::erase( log_id_for_each(i) { for (auto b : mLastWorst[i]) { if (bad == b.second) { - android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i, - b.first, key); + android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n", i, b.first, key); } } for (auto b : mLastWorstPidOfSystem[i]) { if (bad == b.second) { - android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i, - b.first); + android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n", i, b.first); } } } @@ -452,26 +439,20 @@ class LogBufferElementKey { uint64_t value; } __packed; - public: - LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) - : uid(uid), pid(pid), tid(tid) { - } - explicit LogBufferElementKey(uint64_t key) : value(key) { - } + public: + LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) : uid(uid), pid(pid), tid(tid) {} + explicit LogBufferElementKey(uint64_t key) : value(key) {} - uint64_t getKey() { - return value; - } + uint64_t getKey() { return value; } }; class LogBufferElementLast { typedef std::unordered_map LogBufferElementMap; LogBufferElementMap map; - public: + public: bool coalesce(LogBufferElement* element, uint16_t dropped) { - LogBufferElementKey key(element->getUid(), element->getPid(), - element->getTid()); + LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid()); LogBufferElementMap::iterator it = map.find(key.getKey()); if (it != map.end()) { LogBufferElement* found = it->second; @@ -487,14 +468,11 @@ class LogBufferElementLast { } void add(LogBufferElement* element) { - LogBufferElementKey key(element->getUid(), element->getPid(), - element->getTid()); + LogBufferElementKey key(element->getUid(), element->getPid(), element->getTid()); map[key.getKey()] = element; } - inline void clear() { - map.clear(); - } + void clear() { map.clear(); } void clear(LogBufferElement* element) { uint64_t current = element->getRealTime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC); @@ -512,11 +490,11 @@ 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) { +void ChattyLogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) { 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", + android::prdebug("Kicking blocked reader, pid %d, from ChattyLogBuffer::kickMe()\n", me->client()->getPid()); me->release_Locked(); } else if (me->deadline().time_since_epoch().count() != 0) { @@ -525,7 +503,7 @@ void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows } else { // tell slow reader to skip entries to catch up android::prdebug( - "Skipping %lu entries from slow reader, pid %d, from LogBuffer::kickMe()\n", + "Skipping %lu entries from slow reader, pid %d, from ChattyLogBuffer::kickMe()\n", pruneRows, me->client()->getPid()); me->triggerSkip_Locked(id, pruneRows); } @@ -576,9 +554,9 @@ void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows // The third thread is optional, and only gets hit if there was a whitelist // and more needs to be pruned against the backstop of the region lock. // -// LogBuffer::wrlock() must be held when this function is called. +// ChattyLogBuffer::wrlock() must be held when this function is called. // -bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { +bool ChattyLogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { LogReaderThread* oldest = nullptr; bool busy = false; bool clearAll = pruneRows == ULONG_MAX; @@ -606,8 +584,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { while (it != mLogElements.end()) { LogBufferElement* element = *it; - if ((element->getLogId() != id) || - (element->getUid() != caller_uid)) { + if (element->getLogId() != id || element->getUid() != caller_uid) { ++it; continue; } @@ -666,10 +643,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { bool gc = pruneRows <= 1; if (!gc && (worst != -1)) { { // begin scope for worst found iterator - LogBufferIteratorMap::iterator found = - mLastWorst[id].find(worst); - if ((found != mLastWorst[id].end()) && - (found->second != mLogElements.end())) { + LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst); + if (found != mLastWorst[id].end() && found->second != mLogElements.end()) { leading = false; it = found->second; } @@ -677,10 +652,9 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (worstPid) { // begin scope for pid worst found iterator // FYI: worstPid only set if !LOG_ID_EVENTS and // !LOG_ID_SECURITY, not going to make that assumption ... - LogBufferPidIteratorMap::iterator found = - mLastWorstPidOfSystem[id].find(worstPid); - if ((found != mLastWorstPidOfSystem[id].end()) && - (found->second != mLogElements.end())) { + LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid); + if (found != mLastWorstPidOfSystem[id].end() && + found->second != mLogElements.end()) { leading = false; it = found->second; } @@ -689,7 +663,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (leading) { it = GetOldest(id); } - static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 }; + static const timespec too_old = {EXPIRE_HOUR_THRESHOLD * 60 * 60, 0}; LogBufferElementCollection::iterator lastt; lastt = mLogElements.end(); --lastt; @@ -722,9 +696,8 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { continue; } - int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) - ? element->getTag() - : element->getUid(); + int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->getTag() + : element->getUid(); if (hasBlacklist && prune_->naughty(element)) { last.clear(element); @@ -755,10 +728,9 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (dropped) { last.add(element); - if (worstPid && - ((!gc && (element->getPid() == worstPid)) || - (mLastWorstPidOfSystem[id].find(element->getPid()) == - mLastWorstPidOfSystem[id].end()))) { + if (worstPid && ((!gc && element->getPid() == worstPid) || + mLastWorstPidOfSystem[id].find(element->getPid()) == + mLastWorstPidOfSystem[id].end())) { // element->getUid() may not be AID_SYSTEM, next best // watermark if current one empty. id is not LOG_ID_EVENTS // or LOG_ID_SECURITY because of worstPid check. @@ -772,8 +744,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { continue; } - if ((key != worst) || - (worstPid && (element->getPid() != worstPid))) { + if (key != worst || (worstPid && element->getPid() != worstPid)) { leading = false; last.clear(element); ++it; @@ -801,16 +772,14 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { it = erase(it, true); } else { last.add(element); - if (worstPid && - (!gc || (mLastWorstPidOfSystem[id].find(worstPid) == - mLastWorstPidOfSystem[id].end()))) { + if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) == + mLastWorstPidOfSystem[id].end())) { // element->getUid() may not be AID_SYSTEM, next best // watermark if current one empty. id is not // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid. mLastWorstPidOfSystem[id][worstPid] = it; } - if ((!gc && !worstPid) || - (mLastWorst[id].find(worst) == mLastWorst[id].end())) { + if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) { mLastWorst[id][worst] = it; } ++it; @@ -882,7 +851,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } // clear all rows of type "id" from the buffer. -bool LogBuffer::clear(log_id_t id, uid_t uid) { +bool ChattyLogBuffer::Clear(log_id_t id, uid_t uid) { bool busy = true; // If it takes more than 4 tries (seconds) to clear, then kill reader(s) for (int retry = 4;;) { @@ -903,7 +872,7 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) { for (const auto& reader_thread : reader_list_->reader_threads()) { if (reader_thread->IsWatching(id)) { android::prdebug( - "Kicking blocked reader, pid %d, from LogBuffer::clear()\n", + "Kicking blocked reader, pid %d, from ChattyLogBuffer::clear()\n", reader_thread->client()->getPid()); reader_thread->release_Locked(); } @@ -922,7 +891,7 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) { } // set the total space allocated to "id" -int LogBuffer::setSize(log_id_t id, unsigned long size) { +int ChattyLogBuffer::SetSize(log_id_t id, unsigned long size) { // Reasonable limits ... if (!__android_logger_valid_buffer_size(size)) { return -1; @@ -934,14 +903,14 @@ int LogBuffer::setSize(log_id_t id, unsigned long size) { } // get the total space allocated to "id" -unsigned long LogBuffer::getSize(log_id_t id) { +unsigned long ChattyLogBuffer::GetSize(log_id_t id) { rdlock(); size_t retval = log_buffer_size(id); unlock(); return retval; } -uint64_t LogBuffer::flushTo( +uint64_t ChattyLogBuffer::FlushTo( SocketClient* reader, uint64_t start, pid_t* lastTid, bool privileged, bool security, const std::function& filter) { LogBufferElementCollection::iterator it; @@ -999,7 +968,7 @@ uint64_t LogBuffer::flushTo( // is due to spam filter. chatty to chatty of different // source is also due to spam filter. lastTid[element->getLogId()] = - (element->getDropped() && !sameTid) ? 0 : element->getTid(); + (element->getDropped() && !sameTid) ? 0 : element->getTid(); } unlock(); diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h new file mode 100644 index 000000000..d9cd24f11 --- /dev/null +++ b/logd/ChattyLogBuffer.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012-2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +#include "LogBuffer.h" +#include "LogBufferElement.h" +#include "LogStatistics.h" +#include "LogTags.h" +#include "LogWhiteBlackList.h" + +typedef std::list LogBufferElementCollection; + +class LogReaderList; +class LogReaderThread; + +class ChattyLogBuffer : public LogBuffer { + LogBufferElementCollection mLogElements; + pthread_rwlock_t mLogElementsLock; + + // watermark of any worst/chatty uid processing + typedef std::unordered_map LogBufferIteratorMap; + LogBufferIteratorMap mLastWorst[LOG_ID_MAX]; + // watermark of any worst/chatty pid of system processing + typedef std::unordered_map LogBufferPidIteratorMap; + LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX]; + + unsigned long mMaxSize[LOG_ID_MAX]; + + LogBufferElement* lastLoggedElements[LOG_ID_MAX]; + LogBufferElement* droppedElements[LOG_ID_MAX]; + void log(LogBufferElement* elem); + + public: + ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, + LogStatistics* stats); + ~ChattyLogBuffer(); + void Init() override; + + int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg, + uint16_t len) override; + uint64_t FlushTo( + SocketClient* writer, uint64_t start, pid_t* lastTid, bool privileged, bool security, + const std::function& filter) override; + + bool Clear(log_id_t id, uid_t uid = AID_ROOT) override; + unsigned long GetSize(log_id_t id) override; + int SetSize(log_id_t id, unsigned long size) override; + + private: + void wrlock() { pthread_rwlock_wrlock(&mLogElementsLock); } + void rdlock() { pthread_rwlock_rdlock(&mLogElementsLock); } + void unlock() { pthread_rwlock_unlock(&mLogElementsLock); } + + void maybePrune(log_id_t id); + void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows); + + bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); + LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it, + bool coalesce = false); + + // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if + // there are no logs for the given log type. Requires mLogElementsLock to be held. + LogBufferElementCollection::iterator GetOldest(log_id_t log_id); + + LogReaderList* reader_list_; + 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. + std::optional oldest_[LOG_ID_MAX]; +}; diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp index 87402acc3..0ff19f859 100644 --- a/logd/CommandListener.cpp +++ b/logd/CommandListener.cpp @@ -81,7 +81,7 @@ int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc, return 0; } - cli->sendMsg(buf()->clear((log_id_t)id, uid) ? "busy" : "success"); + cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "busy" : "success"); return 0; } @@ -99,7 +99,7 @@ int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc, return 0; } - unsigned long size = buf()->getSize((log_id_t)id); + unsigned long size = buf()->GetSize((log_id_t)id); char buf[512]; snprintf(buf, sizeof(buf), "%lu", size); cli->sendMsg(buf); @@ -126,7 +126,7 @@ int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc, } unsigned long size = atol(argv[2]); - if (buf()->setSize((log_id_t)id, size)) { + if (buf()->SetSize((log_id_t)id, size)) { cli->sendMsg("Range Error"); return 0; } @@ -299,7 +299,7 @@ int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/, setname(); android::prdebug("logd reinit"); - buf()->init(); + buf()->Init(); prune()->init(nullptr); // This only works on userdebug and eng devices to re-read the diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index 520acaf5e..0ce9796b0 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -274,9 +274,8 @@ int LogAudit::logPrint(const char* fmt, ...) { memcpy(event->data + str_len - denial_metadata.length(), denial_metadata.c_str(), denial_metadata.length()); - rc = logbuf->log( - LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast(event), - (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX); + rc = logbuf->Log(LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast(event), + (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX); if (rc >= 0) { notify |= 1 << LOG_ID_EVENTS; } @@ -328,9 +327,8 @@ int LogAudit::logPrint(const char* fmt, ...) { strncpy(newstr + 1 + str_len + prefix_len + suffix_len, denial_metadata.c_str(), denial_metadata.length()); - rc = logbuf->log( - LOG_ID_MAIN, now, uid, pid, tid, newstr, - (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX); + rc = logbuf->Log(LOG_ID_MAIN, now, uid, pid, tid, newstr, + (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX); if (rc >= 0) { notify |= 1 << LOG_ID_MAIN; diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index efcd2af42..887e5f0e4 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2014 The Android Open Source Project + * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,23 +18,12 @@ #include -#include -#include -#include +#include -#include -#include +#include #include #include "LogBufferElement.h" -#include "LogStatistics.h" -#include "LogTags.h" -#include "LogWhiteBlackList.h" - -typedef std::list LogBufferElementCollection; - -class LogReaderList; -class LogReaderThread; enum class FlushToResult { kSkip, @@ -43,71 +32,23 @@ enum class FlushToResult { }; class LogBuffer { - LogBufferElementCollection mLogElements; - pthread_rwlock_t mLogElementsLock; - - // watermark of any worst/chatty uid processing - typedef std::unordered_map - LogBufferIteratorMap; - LogBufferIteratorMap mLastWorst[LOG_ID_MAX]; - // watermark of any worst/chatty pid of system processing - typedef std::unordered_map - LogBufferPidIteratorMap; - LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX]; - - unsigned long mMaxSize[LOG_ID_MAX]; - - LogBufferElement* lastLoggedElements[LOG_ID_MAX]; - LogBufferElement* droppedElements[LOG_ID_MAX]; - void log(LogBufferElement* elem); - public: - LogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune, LogStatistics* stats); - ~LogBuffer(); - void init(); + virtual ~LogBuffer() {} - int log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg, - uint16_t len); + virtual void Init() = 0; + + virtual int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len) = 0; // lastTid is an optional context to help detect if the last previous // valid message was from the same source so we can differentiate chatty // filter types (identical or expired) - uint64_t flushTo(SocketClient* writer, uint64_t start, - pid_t* lastTid, // &lastTid[LOG_ID_MAX] or nullptr - bool privileged, bool security, - const std::function& filter); + virtual uint64_t FlushTo( + SocketClient* writer, uint64_t start, + pid_t* last_tid, // nullable + bool privileged, bool security, + const std::function& filter) = 0; - 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); - - private: - void wrlock() { - pthread_rwlock_wrlock(&mLogElementsLock); - } - void rdlock() { - pthread_rwlock_rdlock(&mLogElementsLock); - } - void unlock() { - pthread_rwlock_unlock(&mLogElementsLock); - } - - void maybePrune(log_id_t id); - void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows); - - bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); - LogBufferElementCollection::iterator erase( - LogBufferElementCollection::iterator it, bool coalesce = false); - - // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if - // there are no logs for the given log type. Requires mLogElementsLock to be held. - LogBufferElementCollection::iterator GetOldest(log_id_t log_id); - - LogReaderList* reader_list_; - 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. - std::optional oldest_[LOG_ID_MAX]; -}; + virtual bool Clear(log_id_t id, uid_t uid) = 0; + virtual unsigned long GetSize(log_id_t id) = 0; + virtual int SetSize(log_id_t id, unsigned long size) = 0; +}; \ No newline at end of file diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index cc68ba4de..32f641b4e 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -27,9 +27,9 @@ #include #include -#include "LogBuffer.h" #include "LogCommand.h" #include "LogReader.h" +#include "LogStatistics.h" #include "LogUtils.h" const uint64_t LogBufferElement::FLUSH_ERROR(0); diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index 8676cf173..3d0b65e59 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -24,7 +24,6 @@ #include #include -class LogBuffer; class LogStatistics; #define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve @@ -34,8 +33,6 @@ class LogStatistics; #define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration class __attribute__((packed)) LogBufferElement { - friend LogBuffer; - // sized to match reality of incoming log packets const uint32_t mUid; const uint32_t mPid; diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index 5242dc3a5..1ea87a91f 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp @@ -767,7 +767,7 @@ int LogKlog::log(const char* buf, ssize_t len) { } // Log message - int rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n); + int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n); return rc; } diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp index 20578861b..6880dbfc6 100644 --- a/logd/LogListener.cpp +++ b/logd/LogListener.cpp @@ -120,7 +120,7 @@ void LogListener::HandleData() { // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a // truncated message to the logs. - logbuf_->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg, + logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg, ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX); } diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp index cc515426d..6f913720a 100644 --- a/logd/LogReader.cpp +++ b/logd/LogReader.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include "LogBuffer.h" @@ -158,7 +159,7 @@ bool LogReader::onDataAvailable(SocketClient* cli) { return FlushToResult::kSkip; }; - log_buffer_->flushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start); + log_buffer_->FlushTo(cli, sequence, nullptr, privileged, can_read_security, log_find_start); if (!start_time_set) { if (nonBlock) { diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp index 4889c2413..e58e3ebde 100644 --- a/logd/LogReaderThread.cpp +++ b/logd/LogReaderThread.cpp @@ -84,13 +84,13 @@ void LogReaderThread::ThreadFunction() { lock.unlock(); if (tail_) { - logbuf.flushTo(client, start, nullptr, privileged_, can_read_security_logs_, + logbuf.FlushTo(client, start, nullptr, privileged_, can_read_security_logs_, std::bind(&LogReaderThread::FilterFirstPass, this, _1)); leading_dropped_ = true; // TODO: Likely a bug, if leading_dropped_ was not true before calling // flushTo(), then it should not be reset to true after. } - start = logbuf.flushTo(client, start, last_tid_, privileged_, can_read_security_logs_, + start = logbuf.FlushTo(client, start, last_tid_, privileged_, can_read_security_logs_, std::bind(&LogReaderThread::FilterSecondPass, this, _1)); // We only ignore entries before the original start time for the first flushTo(), if we diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h index ce59cbbe2..f828b6ec9 100644 --- a/logd/LogReaderThread.h +++ b/logd/LogReaderThread.h @@ -33,6 +33,7 @@ class LogReader; class LogBufferElement; +class LogReaderList; class LogReaderThread { public: diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp index 299242db6..f65fbdfe6 100644 --- a/logd/fuzz/Android.bp +++ b/logd/fuzz/Android.bp @@ -25,6 +25,7 @@ cc_fuzz { "liblog", "liblogd", "libcutils", + "libsysutils", ], cflags: ["-Werror"], } diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp index 3a18f258d..8f90f5068 100644 --- a/logd/fuzz/log_buffer_log_fuzzer.cpp +++ b/logd/fuzz/log_buffer_log_fuzzer.cpp @@ -15,7 +15,7 @@ */ #include -#include "../LogBuffer.h" +#include "../ChattyLogBuffer.h" #include "../LogReaderList.h" #include "../LogReaderThread.h" #include "../LogStatistics.h" @@ -72,7 +72,7 @@ int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_ // Other elements not in enum. 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, + log_buffer->Log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg, sizeof(uint32_t) + msg_length + 1); stats->Format(logInput->uid, logInput->pid, logInput->log_mask); *pdata = data; @@ -100,21 +100,21 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { LogTags tags; PruneList prune_list; LogStatistics stats(true); - LogBuffer log_buffer(&reader_list, &tags, &prune_list, &stats); + LogBuffer* log_buffer = new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats); size_t data_left = size; const uint8_t** pdata = &data; prune_list.init(nullptr); // We want to get pruning code to get called. - log_id_for_each(i) { log_buffer.setSize(i, 10000); } + 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, &stats)) { + if (!write_log_messages(pdata, &data_left, log_buffer, &stats)) { return 0; } } - log_id_for_each(i) { log_buffer.clear(i); } + log_id_for_each(i) { log_buffer->Clear(i, 0); } return 0; } } // namespace android diff --git a/logd/main.cpp b/logd/main.cpp index a7b89b859..6e1144b67 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -47,6 +47,7 @@ #include #include +#include "ChattyLogBuffer.h" #include "CommandListener.h" #include "LogAudit.h" #include "LogBuffer.h" @@ -288,7 +289,7 @@ int main(int argc, char* argv[]) { // LogBuffer is the object which is responsible for holding all // log entries. - LogBuffer* logBuf = new LogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics); + LogBuffer* logBuf = new ChattyLogBuffer(&reader_list, &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.