Merge changes I9d6dde2c,I38bfcba5 am: a269c7c3d1 am: 0379e27671 am: a0f8962885

Change-Id: Ic29b7b0718a7b9415a8e7569706a29f5d127ef3b
This commit is contained in:
Tom Cherry 2020-05-12 16:37:12 +00:00 committed by Automerger Merge Worker
commit c226504862
17 changed files with 343 additions and 367 deletions

View file

@ -54,6 +54,7 @@ cc_library_static {
cflags: [
"-Wextra",
"-Wthread-safety",
] + event_flag,
}

View file

@ -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 @@ int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc,
return 0;
}
unsigned long size = buf()->getSizeUsed((log_id_t)id);
unsigned long size = stats()->Sizes((log_id_t)id);
char buf[512];
snprintf(buf, sizeof(buf), "%lu", size);
cli->sendMsg(buf);
@ -209,7 +210,7 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
}
}
cli->sendMsg(PackageString(buf()->formatStatistics(uid, pid, logMask)).c_str());
cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str());
return 0;
}

View file

@ -22,12 +22,13 @@
#include "LogCommand.h"
#include "LogListener.h"
#include "LogReader.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogWhiteBlackList.h"
class CommandListener : public FrameworkListener {
public:
CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune);
CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics);
virtual ~CommandListener() {}
private:
@ -36,20 +37,22 @@ class CommandListener : public FrameworkListener {
LogBuffer* buf_;
LogTags* tags_;
PruneList* prune_;
LogStatistics* stats_;
#define LogCmd(name, command_string) \
class name##Cmd : public LogCommand { \
public: \
explicit name##Cmd(CommandListener* parent) \
: LogCommand(#command_string), parent_(parent) {} \
virtual ~name##Cmd() {} \
int runCommand(SocketClient* c, int argc, char** argv); \
\
private: \
LogBuffer* buf() const { return parent_->buf_; } \
LogTags* tags() const { return parent_->tags_; } \
PruneList* prune() const { return parent_->prune_; } \
CommandListener* parent_; \
#define LogCmd(name, command_string) \
class name##Cmd : public LogCommand { \
public: \
explicit name##Cmd(CommandListener* parent) \
: LogCommand(#command_string), parent_(parent) {} \
virtual ~name##Cmd() {} \
int runCommand(SocketClient* c, int argc, char** argv); \
\
private: \
LogBuffer* buf() const { return parent_->buf_; } \
LogTags* tags() const { return parent_->tags_; } \
PruneList* prune() const { return parent_->prune_; } \
LogStatistics* stats() const { return parent_->stats_; } \
CommandListener* parent_; \
}
LogCmd(Clear, clear);

View file

@ -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 @@ int LogAudit::logPrint(const char* fmt, ...) {
++cp;
}
tid = pid;
logbuf->wrlock();
uid = logbuf->pidToUid(pid);
logbuf->unlock();
uid = stats_->PidToUid(pid);
memmove(pidptr, cp, strlen(cp) + 1);
}
@ -301,9 +298,7 @@ int LogAudit::logPrint(const char* fmt, ...) {
pid = tid;
comm = "auditd";
} else {
logbuf->wrlock();
comm = commfree = logbuf->pidToName(pid);
logbuf->unlock();
comm = commfree = stats_->PidToName(pid);
if (!comm) {
comm = "unknown";
}

View file

@ -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 @@ class LogAudit : public SocketListener {
bool events;
bool initialized;
public:
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg);
public:
LogAudit(LogBuffer* buf, LogReader* reader, int fdDmesg, LogStatistics* stats);
int log(char* buf, size_t len);
protected:
protected:
virtual bool onDataAvailable(SocketClient* cli);
private:
private:
static int getLogSocket();
std::map<std::string, std::string> populateDenialMap();
std::string denialParse(const std::string& denial, char terminator,
@ -48,6 +48,6 @@ class LogAudit : public SocketListener {
void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
int logPrint(const char* fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
};
#endif
LogStatistics* stats_;
};

View file

@ -63,8 +63,8 @@ void LogBuffer::init() {
LogReaderThread::unlock();
}
LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune)
: mTimes(*times), tags_(tags), prune_(prune) {
LogBuffer::LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats)
: mTimes(*times), tags_(tags), prune_(prune), stats_(stats) {
pthread_rwlock_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
@ -197,9 +197,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
}
if (!__android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE)) {
// Log traffic received to total
wrlock();
stats.addTotal(elem);
unlock();
stats_->AddTotal(elem);
delete elem;
return -EACCES;
}
@ -308,7 +306,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
unlock();
return len;
}
stats.addTotal(currentLast);
stats_->AddTotal(currentLast);
delete currentLast;
swab = total;
event->payload.data = htole32(swab);
@ -324,7 +322,7 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
}
}
if (count) {
stats.addTotal(currentLast);
stats_->AddTotal(currentLast);
currentLast->setDropped(count);
}
droppedElements[log_id] = currentLast;
@ -355,31 +353,15 @@ int LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
void LogBuffer::log(LogBufferElement* elem) {
mLogElements.push_back(elem);
stats.add(elem);
stats_->Add(elem);
maybePrune(elem->getLogId());
}
// Prune at most 10% of the log entries or maxPrune, whichever is less.
//
// LogBuffer::wrlock() must be held when this function is called.
void LogBuffer::maybePrune(log_id_t id) {
size_t sizes = stats.sizes(id);
unsigned long maxSize = log_buffer_size(id);
if (sizes > maxSize) {
size_t sizeOver = sizes - ((maxSize * 9) / 10);
size_t elements = stats.realElements(id);
size_t minElements = elements / 100;
if (minElements < minPrune) {
minElements = minPrune;
}
unsigned long pruneRows = elements * sizeOver / sizes;
if (pruneRows < minElements) {
pruneRows = minElements;
}
if (pruneRows > maxPrune) {
pruneRows = maxPrune;
}
prune(id, pruneRows);
unsigned long prune_rows;
if (stats_->ShouldPrune(id, log_buffer_size(id), &prune_rows)) {
prune(id, prune_rows);
}
}
@ -452,9 +434,9 @@ LogBufferElementCollection::iterator LogBuffer::erase(
}
#endif
if (coalesce) {
stats.erase(element);
stats_->Erase(element);
} else {
stats.subtract(element);
stats_->Subtract(element);
}
delete element;
@ -535,7 +517,7 @@ class LogBufferElementLast {
// If the selected reader is blocking our pruning progress, decide on
// what kind of mitigation is necessary to unblock the situation.
void LogBuffer::kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows) {
if (stats.sizes(id) > (2 * log_buffer_size(id))) { // +100%
if (stats_->Sizes(id) > (2 * log_buffer_size(id))) { // +100%
// A misbehaving or slow reader has its connection
// dropped if we hit too much memory pressure.
android::prdebug("Kicking blocked reader, pid %d, from LogBuffer::kickMe()\n",
@ -663,19 +645,14 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
// Calculate threshold as 12.5% of available storage
size_t threshold = log_buffer_size(id) / 8;
if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
stats.sortTags(AID_ROOT, (pid_t)0, 2, id)
.findWorst(worst, worst_sizes, second_worst_sizes,
threshold);
if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
stats_->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
// per-pid filter for AID_SYSTEM sources is too complex
} else {
stats.sort(AID_ROOT, (pid_t)0, 2, id)
.findWorst(worst, worst_sizes, second_worst_sizes,
threshold);
stats_->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
if ((worst == AID_SYSTEM) && prune_->worstPidOfSystemEnabled()) {
stats.sortPids(worst, (pid_t)0, 2, id)
.findWorst(worstPid, worst_sizes, second_worst_sizes);
if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
stats_->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
}
}
}
@ -824,7 +801,7 @@ bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
if (leading) {
it = erase(it);
} else {
stats.drop(element);
stats_->Drop(element);
element->setDropped(1);
if (last.coalesce(element, 1)) {
it = erase(it, true);
@ -957,14 +934,6 @@ bool LogBuffer::clear(log_id_t id, uid_t uid) {
return busy;
}
// get the used space associated with "id".
unsigned long LogBuffer::getSizeUsed(log_id_t id) {
rdlock();
size_t retval = stats.sizes(id);
unlock();
return retval;
}
// set the total space allocated to "id"
int LogBuffer::setSize(log_id_t id, unsigned long size) {
// Reasonable limits ...
@ -1049,7 +1018,7 @@ uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid
unlock();
// range locking in LastLogTimes looks after us
curr = element->flushTo(reader, this, sameTid);
curr = element->flushTo(reader, stats_, sameTid);
if (curr == element->FLUSH_ERROR) {
return curr;
@ -1061,14 +1030,3 @@ uint64_t LogBuffer::flushTo(SocketClient* reader, uint64_t start, pid_t* lastTid
return curr;
}
std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
unsigned int logMask) {
wrlock();
std::string ret = stats.format(uid, pid, logMask);
unlock();
return ret;
}

View file

@ -38,8 +38,6 @@ class LogBuffer {
LogBufferElementCollection mLogElements;
pthread_rwlock_t mLogElementsLock;
LogStatistics stats;
// watermark of any worst/chatty uid processing
typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
LogBufferIteratorMap;
@ -58,7 +56,7 @@ class LogBuffer {
public:
LastLogTimes& mTimes;
LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune);
LogBuffer(LastLogTimes* times, LogTags* tags, PruneList* prune, LogStatistics* stats);
~LogBuffer();
void init();
@ -75,22 +73,8 @@ class LogBuffer {
bool clear(log_id_t id, uid_t uid = AID_ROOT);
unsigned long getSize(log_id_t id);
int setSize(log_id_t id, unsigned long size);
unsigned long getSizeUsed(log_id_t id);
std::string formatStatistics(uid_t uid, pid_t pid, unsigned int logMask);
void enableStatistics() {
stats.enableStatistics();
}
// helper must be protected directly or implicitly by wrlock()/unlock()
const char* pidToName(pid_t pid) {
return stats.pidToName(pid);
}
uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
const char* uidToName(uid_t uid) {
return stats.uidToName(uid);
}
private:
void wrlock() {
pthread_rwlock_wrlock(&mLogElementsLock);
}
@ -101,10 +85,6 @@ class LogBuffer {
pthread_rwlock_unlock(&mLogElementsLock);
}
private:
static constexpr size_t minPrune = 4;
static constexpr size_t maxPrune = 256;
void maybePrune(log_id_t id);
void kickMe(LogReaderThread* me, log_id_t id, unsigned long pruneRows);
@ -118,6 +98,7 @@ class LogBuffer {
LogTags* tags_;
PruneList* prune_;
LogStatistics* stats_;
// Keeps track of the iterator to the oldest log message of a given log type, as an
// optimization when pruning logs. Use GetOldest() to retrieve.

View file

@ -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 @@ char* android::tidToName(pid_t tid) {
}
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent,
size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogStatistics* stats,
bool lastSame) {
static const char tag[] = "chatty";
@ -163,17 +164,13 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent
}
static const char format_uid[] = "uid=%u%s%s %s %u line%s";
parent->wrlock();
const char* name = parent->uidToName(mUid);
parent->unlock();
const char* name = stats->UidToName(mUid);
const char* commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
commName = android::tidToName(mPid);
}
if (!commName) {
parent->wrlock();
commName = parent->pidToName(mPid);
parent->unlock();
commName = stats->PidToName(mPid);
}
if (name && name[0] && commName && (name[0] == commName[0])) {
size_t len = strlen(name + 1);
@ -246,7 +243,7 @@ size_t LogBufferElement::populateDroppedMessage(char*& buffer, LogBuffer* parent
return retval;
}
uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool lastSame) {
uint64_t LogBufferElement::flushTo(SocketClient* reader, LogStatistics* stats, bool lastSame) {
struct logger_entry entry = {};
entry.hdr_size = sizeof(struct logger_entry);
@ -264,7 +261,7 @@ uint64_t LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent, bool
char* buffer = nullptr;
if (mDropped) {
entry.len = populateDroppedMessage(buffer, parent, lastSame);
entry.len = populateDroppedMessage(buffer, stats, lastSame);
if (!entry.len) return mSequence;
iovec[1].iov_base = buffer;
} else {

View file

@ -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 @@ class __attribute__((packed)) LogBufferElement {
static atomic_int_fast64_t sequence;
// assumption: mDropped == true
size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
bool lastSame);
size_t populateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame);
public:
public:
LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
pid_t tid, const char* msg, uint16_t len);
LogBufferElement(const LogBufferElement& elem);
@ -98,5 +98,5 @@ class __attribute__((packed)) LogBufferElement {
}
static const uint64_t FLUSH_ERROR;
uint64_t flushTo(SocketClient* writer, LogBuffer* parent, bool lastSame);
uint64_t flushTo(SocketClient* writer, LogStatistics* parent, bool lastSame);
};

View file

@ -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 LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTO
? log_time(log_time::EPOCH)
: (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
bool auditd)
LogKlog::LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd,
LogStatistics* stats)
: SocketListener(fdRead, false),
logbuf(buf),
reader(reader),
signature(CLOCK_MONOTONIC),
initialized(false),
enableLogging(true),
auditd(auditd) {
auditd(auditd),
stats_(stats) {
static const char klogd_message[] = "%s%s%" PRIu64 "\n";
char buffer[strlen(priority_message) + strlen(klogdStr) +
strlen(klogd_message) + 20];
@ -528,9 +530,7 @@ int LogKlog::log(const char* buf, ssize_t len) {
const pid_t tid = pid;
uid_t uid = AID_ROOT;
if (pid) {
logbuf->wrlock();
uid = logbuf->pidToUid(pid);
logbuf->unlock();
uid = stats_->PidToUid(pid);
}
// Parse (rules at top) to pull out a tag from the incoming kernel message.

View file

@ -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 @@ class LogKlog : public SocketListener {
static log_time correction;
public:
LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead,
bool auditd);
public:
LogKlog(LogBuffer* buf, LogReader* reader, int fdWrite, int fdRead, bool auditd,
LogStatistics* stats);
int log(const char* buf, ssize_t len);
static void convertMonotonicToReal(log_time& real) {
real += correction;
}
static void convertMonotonicToReal(log_time& real) { real += correction; }
protected:
log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
pid_t sniffPid(const char*& buf, ssize_t len);
void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
virtual bool onDataAvailable(SocketClient* cli);
protected:
log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
pid_t sniffPid(const char*& buf, ssize_t len);
void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
virtual bool onDataAvailable(SocketClient* cli);
private:
LogStatistics* stats_;
};
#endif

View file

@ -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 @@ char* pidToName(pid_t pid) {
}
}
void LogStatistics::addTotal(LogBufferElement* element) {
void LogStatistics::AddTotal(LogBufferElement* element) {
auto lock = std::lock_guard{lock_};
if (element->getDropped()) return;
log_id_t log_id = element->getLogId();
@ -89,7 +90,8 @@ void LogStatistics::addTotal(LogBufferElement* element) {
++mElementsTotal[log_id];
}
void LogStatistics::add(LogBufferElement* element) {
void LogStatistics::Add(LogBufferElement* element) {
auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] += size;
@ -159,7 +161,8 @@ void LogStatistics::add(LogBufferElement* element) {
}
}
void LogStatistics::subtract(LogBufferElement* element) {
void LogStatistics::Subtract(LogBufferElement* element) {
auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] -= size;
@ -204,7 +207,8 @@ void LogStatistics::subtract(LogBufferElement* element) {
// Atomically set an entry to drop
// entry->setDropped(1) must follow this call, caller should do this explicitly.
void LogStatistics::drop(LogBufferElement* element) {
void LogStatistics::Drop(LogBufferElement* element) {
auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
uint16_t size = element->getMsgLen();
mSizes[log_id] -= size;
@ -238,9 +242,13 @@ void LogStatistics::drop(LogBufferElement* element) {
tagNameTable.subtract(TagNameKey(element), element);
}
const char* LogStatistics::UidToName(uid_t uid) const {
auto lock = std::lock_guard{lock_};
return UidToNameLocked(uid);
}
// caller must own and free character string
// Requires parent LogBuffer::wrlock() to be held
const char* LogStatistics::uidToName(uid_t uid) const {
const char* LogStatistics::UidToNameLocked(uid_t uid) const {
// Local hard coded favourites
if (uid == AID_LOGD) {
return strdup("auditd");
@ -297,6 +305,80 @@ const char* LogStatistics::uidToName(uid_t uid) const {
return name;
}
template <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) const {
std::array<const TEntry*, 2> max_entries;
table.MaxEntries(AID_ROOT, 0, &max_entries);
if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
return;
}
*worst_sizes = max_entries[0]->getSizes();
// b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
// 100 characters.
if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->getDropped())) {
*worst = max_entries[0]->getKey();
*second_worst_sizes = max_entries[1]->getSizes();
if (*second_worst_sizes < threshold) {
*second_worst_sizes = threshold;
}
}
}
void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
size_t* second_worst_sizes) const {
auto lock = std::lock_guard{lock_};
WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
}
void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
size_t* second_worst_sizes) const {
auto lock = std::lock_guard{lock_};
WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
}
void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
size_t* second_worst_sizes) const {
auto lock = std::lock_guard{lock_};
std::array<const PidEntry*, 2> max_entries;
pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, &max_entries);
if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
return;
}
*worst = max_entries[0]->getKey();
*second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
}
// Prune at most 10% of the log entries or maxPrune, whichever is less.
bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
unsigned long* prune_rows) const {
static constexpr size_t kMinPrune = 4;
static constexpr size_t kMaxPrune = 256;
auto lock = std::lock_guard{lock_};
size_t sizes = mSizes[id];
if (sizes <= max_size) {
return false;
}
size_t size_over = sizes - ((max_size * 9) / 10);
size_t elements = mElements[id] - mDroppedElements[id];
size_t min_elements = elements / 100;
if (min_elements < kMinPrune) {
min_elements = kMinPrune;
}
*prune_rows = elements * size_over / sizes;
if (*prune_rows < min_elements) {
*prune_rows = min_elements;
}
if (*prune_rows > kMaxPrune) {
*prune_rows = kMaxPrune;
}
return true;
}
std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
bool isprune = worstUidEnabledForLogid(id);
return formatLine(android::base::StringPrintf(name.c_str(),
@ -308,10 +390,10 @@ std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
}
// Helper to truncate name, if too long, and add name dressings
static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
std::string& name, std::string& size, size_t nameLen) {
void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
size_t nameLen) const {
const char* allocNameTmp = nullptr;
if (!nameTmp) nameTmp = allocNameTmp = stat.uidToName(uid);
if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
if (nameTmp) {
size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
size_t len = EntryBaseConstants::total_len -
@ -332,12 +414,12 @@ static void formatTmp(const LogStatistics& stat, const char* nameTmp, uid_t uid,
}
}
std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const REQUIRES(stat.lock_) {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%u", uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
formatTmp(stat, nullptr, uid, name, size, 6);
stat.FormatTmp(nullptr, uid, name, size, 6);
std::string pruned = "";
if (worstUidEnabledForLogid(id)) {
@ -347,9 +429,9 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
it != stat.uidTable[id].end(); ++it) {
totalDropped += it->second.getDropped();
}
size_t sizes = stat.sizes(id);
size_t totalSize = stat.sizesTotal(id);
size_t totalElements = stat.elementsTotal(id);
size_t sizes = stat.mSizes[id];
size_t totalSize = stat.mSizesTotal[id];
size_t totalElements = stat.mElementsTotal[id];
float totalVirtualSize =
(float)sizes + (float)totalDropped * totalSize / totalElements;
size_t entrySize = getSizes();
@ -401,12 +483,9 @@ std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
}
static const size_t maximum_sorted_entries = 32;
std::unique_ptr<const PidEntry* []> sorted =
stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
std::array<const PidEntry*, maximum_sorted_entries> sorted;
stat.pidSystemTable[id].MaxEntries(uid, 0, &sorted);
if (!sorted.get()) {
return output;
}
std::string byPid;
size_t index;
bool hasDropped = false;
@ -440,14 +519,14 @@ std::string PidEntry::formatHeader(const std::string& name,
std::string("BYTES"), std::string("NUM"));
}
std::string PidEntry::format(const LogStatistics& stat,
log_id_t /* id */) const {
std::string PidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
REQUIRES(stat.lock_) {
uid_t uid = getUid();
pid_t pid = getPid();
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
formatTmp(stat, getName(), uid, name, size, 12);
stat.FormatTmp(getName(), uid, name, size, 12);
std::string pruned = "";
size_t dropped = getDropped();
@ -465,13 +544,13 @@ std::string TidEntry::formatHeader(const std::string& name,
std::string("NUM"));
}
std::string TidEntry::format(const LogStatistics& stat,
log_id_t /* id */) const {
std::string TidEntry::format(const LogStatistics& stat, log_id_t /* id */) const
REQUIRES(stat.lock_) {
uid_t uid = getUid();
std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
std::string size = android::base::StringPrintf("%zu", getSizes());
formatTmp(stat, getName(), uid, name, size, 12);
stat.FormatTmp(getName(), uid, name, size, 12);
std::string pruned = "";
size_t dropped = getDropped();
@ -611,8 +690,36 @@ static std::string formatMsec(uint64_t val) {
return output;
}
std::string LogStatistics::format(uid_t uid, pid_t pid,
unsigned int logMask) const {
template <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
@ -642,9 +749,9 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
if (!(logMask & (1 << id))) continue;
oldLength = output.length();
if (spaces < 0) spaces = 0;
size_t szs = sizesTotal(id);
size_t szs = mSizesTotal[id];
totalSize += szs;
size_t els = elementsTotal(id);
size_t els = mElementsTotal[id];
totalEls += els;
output +=
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
@ -663,11 +770,11 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
size_t els = elements(id);
size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
size_t szs = sizes(id);
size_t szs = mSizes[id];
totalSize += szs;
totalEls += els;
output +=
@ -749,7 +856,7 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
log_id_for_each(id) {
if (!(logMask & (1 << id))) continue;
size_t els = elements(id);
size_t els = mElements[id];
if (els) {
oldLength = output.length();
if (spaces < 0) spaces = 0;
@ -758,7 +865,7 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
-sizeof(uint64_t)) +
sizeof(std::list<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;
@ -779,39 +886,38 @@ std::string LogStatistics::format(uid_t uid, pid_t pid,
name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
: "Logging for your UID in %s log buffer:";
output += uidTable[id].format(*this, uid, pid, name, id);
output += FormatTable(uidTable[id], uid, pid, name, id);
}
if (enable) {
name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
: "Logging for this PID:";
output += pidTable.format(*this, uid, pid, name);
output += FormatTable(pidTable, uid, pid, name);
name = "Chattiest TIDs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
output += tidTable.format(*this, uid, pid, name);
output += FormatTable(tidTable, uid, pid, name);
}
if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
name = "Chattiest events log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
}
if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
name = "Chattiest security log buffer TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
output +=
securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
}
if (enable) {
name = "Chattiest TAGs";
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
name += ":";
output += tagNameTable.format(*this, uid, pid, name);
output += FormatTable(tagNameTable, uid, pid, name);
}
return output;
@ -839,12 +945,14 @@ uid_t pidToUid(pid_t pid) {
}
}
uid_t LogStatistics::pidToUid(pid_t pid) {
uid_t LogStatistics::PidToUid(pid_t pid) {
auto lock = std::lock_guard{lock_};
return pidTable.add(pid)->second.getUid();
}
// caller must free character string
const char* LogStatistics::pidToName(pid_t pid) const {
const char* LogStatistics::PidToName(pid_t pid) const {
auto lock = std::lock_guard{lock_};
// An inconvenient truth ... getName() can alter the object
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
const char* name = writablePidTable.add(pid)->second.getName();

View file

@ -14,8 +14,7 @@
* limitations under the License.
*/
#ifndef _LOGD_LOG_STATISTICS_H__
#define _LOGD_LOG_STATISTICS_H__
#pragma once
#include <ctype.h>
#include <inttypes.h>
@ -25,12 +24,15 @@
#include <sys/types.h>
#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>
@ -79,16 +81,12 @@ class LogHashtable {
typedef
typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
std::unique_ptr<const TEntry* []> sort(uid_t uid, pid_t pid,
size_t len) const {
if (!len) {
std::unique_ptr<const TEntry* []> sorted(nullptr);
return sorted;
}
const TEntry** retval = new const TEntry*[len];
memset(retval, 0, sizeof(*retval) * len);
// Returns a sorted array of up to len highest entries sorted by size. If fewer than len
// entries are found, their positions are set to nullptr.
template <size_t len>
void MaxEntries(uid_t uid, pid_t pid, std::array<const TEntry*, len>* out) const {
auto& retval = *out;
retval.fill(nullptr);
for (const_iterator it = map.begin(); it != map.end(); ++it) {
const TEntry& entry = it->second;
@ -113,8 +111,6 @@ class LogHashtable {
retval[index] = &entry;
}
}
std::unique_ptr<const TEntry* []> sorted(retval);
return sorted;
}
inline iterator add(const TKey& key, const LogBufferElement* element) {
@ -170,35 +166,6 @@ class LogHashtable {
inline const_iterator end() const {
return map.end();
}
std::string format(const LogStatistics& stat, uid_t uid, pid_t pid,
const std::string& name = std::string(""),
log_id_t id = LOG_ID_MAX) const {
static const size_t maximum_sorted_entries = 32;
std::string output;
std::unique_ptr<const TEntry* []> sorted =
sort(uid, pid, maximum_sorted_entries);
if (!sorted.get()) {
return output;
}
bool headerPrinted = false;
for (size_t index = 0; index < maximum_sorted_entries; ++index) {
const TEntry* entry = sorted[index];
if (!entry) {
break;
}
if (entry->getSizes() <= (sorted[0]->getSizes() / 100)) {
break;
}
if (!headerPrinted) {
output += "\n\n";
output += entry->formatHeader(name, id);
headerPrinted = true;
}
output += entry->format(stat, id);
}
return output;
}
};
namespace EntryBaseConstants {
@ -627,84 +594,51 @@ struct TagNameEntry : public EntryBase {
std::string format(const LogStatistics& stat, log_id_t id) const;
};
template <typename TEntry>
class LogFindWorst {
std::unique_ptr<const TEntry* []> sorted;
public:
explicit LogFindWorst(std::unique_ptr<const TEntry* []>&& sorted)
: sorted(std::move(sorted)) {
}
void findWorst(int& worst, size_t& worst_sizes, size_t& second_worst_sizes,
size_t threshold) {
if (sorted.get() && sorted[0] && sorted[1]) {
worst_sizes = sorted[0]->getSizes();
if ((worst_sizes > threshold)
// Allow time horizon to extend roughly tenfold, assume
// average entry length is 100 characters.
&& (worst_sizes > (10 * sorted[0]->getDropped()))) {
worst = sorted[0]->getKey();
second_worst_sizes = sorted[1]->getSizes();
if (second_worst_sizes < threshold) {
second_worst_sizes = threshold;
}
}
}
}
void findWorst(int& worst, size_t worst_sizes, size_t& second_worst_sizes) {
if (sorted.get() && sorted[0] && sorted[1]) {
worst = sorted[0]->getKey();
second_worst_sizes =
worst_sizes - sorted[0]->getSizes() + sorted[1]->getSizes();
}
}
};
// Log Statistics
class LogStatistics {
friend UidEntry;
friend PidEntry;
friend TidEntry;
size_t mSizes[LOG_ID_MAX];
size_t mElements[LOG_ID_MAX];
size_t mDroppedElements[LOG_ID_MAX];
size_t mSizesTotal[LOG_ID_MAX];
size_t mElementsTotal[LOG_ID_MAX];
log_time mOldest[LOG_ID_MAX];
log_time mNewest[LOG_ID_MAX];
log_time mNewestDropped[LOG_ID_MAX];
static size_t SizesTotal;
size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
static std::atomic<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() +
@ -729,62 +663,59 @@ class LogStatistics {
return size;
}
public:
LogStatistics();
public:
LogStatistics(bool enable_statistics);
void enableStatistics() {
enable = true;
}
void addTotal(LogBufferElement* entry);
void add(LogBufferElement* entry);
void subtract(LogBufferElement* entry);
void AddTotal(LogBufferElement* entry) EXCLUDES(lock_);
void Add(LogBufferElement* entry) EXCLUDES(lock_);
void Subtract(LogBufferElement* entry) EXCLUDES(lock_);
// entry->setDropped(1) must follow this call
void drop(LogBufferElement* entry);
void Drop(LogBufferElement* entry) EXCLUDES(lock_);
// Correct for coalescing two entries referencing dropped content
void erase(LogBufferElement* element) {
void Erase(LogBufferElement* element) EXCLUDES(lock_) {
auto lock = std::lock_guard{lock_};
log_id_t log_id = element->getLogId();
--mElements[log_id];
--mDroppedElements[log_id];
}
LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
}
LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len,
log_id id) {
return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
}
LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
}
void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
size_t* second_worst_sizes) const EXCLUDES(lock_);
void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
size_t* second_worst_sizes) const EXCLUDES(lock_);
void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
size_t* second_worst_sizes) const EXCLUDES(lock_);
// fast track current value by id only
size_t sizes(log_id_t id) const {
bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
EXCLUDES(lock_);
// Snapshot of the sizes for a given log buffer.
size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
auto lock = std::lock_guard{lock_};
return mSizes[id];
}
size_t elements(log_id_t id) const {
return mElements[id];
}
size_t realElements(log_id_t id) const {
return mElements[id] - mDroppedElements[id];
}
size_t sizesTotal(log_id_t id) const {
return mSizesTotal[id];
}
size_t elementsTotal(log_id_t id) const {
return mElementsTotal[id];
}
// TODO: Get rid of this entirely.
static size_t sizesTotal() {
return SizesTotal;
}
std::string format(uid_t uid, pid_t pid, unsigned int logMask) const;
std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
// helper (must be locked directly or implicitly by mLogElementsLock)
const char* pidToName(pid_t pid) const;
uid_t pidToUid(pid_t pid);
const char* uidToName(uid_t uid) const;
const char* PidToName(pid_t pid) const EXCLUDES(lock_);
uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
const char* UidToName(uid_t uid) const EXCLUDES(lock_);
private:
template <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) 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_;
};
#endif // _LOGD_LOG_STATISTICS_H__

View file

@ -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 @@ void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
// Every 16K (half the smallest configurable pmsg buffer size) record
static const size_t rate_to_pmsg = 16 * 1024;
if (lastTotal && ((android::sizesTotal() - lastTotal) < rate_to_pmsg)) {
if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
return;
}
@ -663,7 +664,7 @@ void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
}
}
lastTotal = android::sizesTotal();
lastTotal = LogStatistics::sizesTotal();
if (!lastTotal) ++lastTotal;
// record totals for next watermark.

View file

@ -32,8 +32,6 @@ namespace android {
char* uidToName(uid_t uid);
void prdebug(const char* fmt, ...) __printflike(1, 2);
// Furnished in LogStatistics.cpp.
size_t sizesTotal();
// Caller must own and free returned value
char* pidToName(pid_t pid);
char* tidToName(pid_t tid);

View file

@ -17,6 +17,7 @@
#include "../LogBuffer.h"
#include "../LogReaderThread.h"
#include "../LogStatistics.h"
// We don't want to waste a lot of entropy on messages
#define MAX_MSG_LENGTH 5
@ -36,7 +37,8 @@ struct LogInput {
unsigned int log_mask;
};
int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer) {
int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer,
LogStatistics* stats) {
const uint8_t* data = *pdata;
const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
data += sizeof(LogInput);
@ -71,7 +73,7 @@ int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_
log_id_t log_id = static_cast<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 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
LastLogTimes times;
LogTags tags;
PruneList prune_list;
LogBuffer log_buffer(&times, &tags, &prune_list);
LogStatistics stats(true);
LogBuffer log_buffer(&times, &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;
}
}

View file

@ -52,6 +52,7 @@
#include "LogBuffer.h"
#include "LogKlog.h"
#include "LogListener.h"
#include "LogStatistics.h"
#include "LogTags.h"
#include "LogUtils.h"
@ -272,6 +273,11 @@ int main(int argc, char* argv[]) {
LogTags log_tags;
// Pruning configuration.
PruneList prune_list;
// Partial (required for chatty) or full logging statistics.
bool enable_full_log_statistics = __android_logger_property_get_bool(
"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
LogStatistics log_statistics(enable_full_log_statistics);
// Serves the purpose of managing the last logs times read on a
// socket connection, and as a reader lock on a range of log
@ -282,14 +288,7 @@ int main(int argc, char* argv[]) {
// LogBuffer is the object which is responsible for holding all
// log entries.
LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list);
if (__android_logger_property_get_bool(
"logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
BOOL_DEFAULT_FLAG_ENG |
BOOL_DEFAULT_FLAG_SVELTE)) {
logBuf->enableStatistics();
}
LogBuffer* logBuf = new LogBuffer(times, &log_tags, &prune_list, &log_statistics);
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
@ -311,7 +310,7 @@ int main(int argc, char* argv[]) {
// Command listener listens on /dev/socket/logd for incoming logd
// administrative commands.
CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list);
CommandListener* cl = new CommandListener(logBuf, &log_tags, &prune_list, &log_statistics);
if (cl->startListener()) {
return EXIT_FAILURE;
}
@ -322,16 +321,17 @@ int main(int argc, char* argv[]) {
LogAudit* al = nullptr;
if (auditd) {
al = new LogAudit(logBuf, reader,
__android_logger_property_get_bool(
"ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
? fdDmesg
: -1);
al = new LogAudit(
logBuf, reader,
__android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
? fdDmesg
: -1,
&log_statistics);
}
LogKlog* kl = nullptr;
if (klogd) {
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
}
readDmesg(al, kl);