diff options
Diffstat (limited to 'logd')
-rw-r--r-- | logd/Android.mk | 11 | ||||
-rw-r--r-- | logd/CommandListener.cpp | 16 | ||||
-rw-r--r-- | logd/CommandListener.h | 11 | ||||
-rw-r--r-- | logd/FlushCommand.cpp | 2 | ||||
-rw-r--r-- | logd/FlushCommand.h | 4 | ||||
-rw-r--r-- | logd/LogAudit.cpp | 41 | ||||
-rw-r--r-- | logd/LogBuffer.cpp | 70 | ||||
-rw-r--r-- | logd/LogBuffer.h | 11 | ||||
-rw-r--r-- | logd/LogBufferElement.cpp | 9 | ||||
-rw-r--r-- | logd/LogBufferElement.h | 11 | ||||
-rw-r--r-- | logd/LogReader.cpp | 38 | ||||
-rw-r--r-- | logd/LogStatistics.cpp | 109 | ||||
-rw-r--r-- | logd/LogStatistics.h | 5 | ||||
-rw-r--r-- | logd/LogTimes.cpp | 24 | ||||
-rw-r--r-- | logd/LogTimes.h | 11 | ||||
-rw-r--r-- | logd/README.property | 6 | ||||
-rw-r--r-- | logd/main.cpp | 139 | ||||
-rw-r--r-- | logd/tests/logd_test.cpp | 158 |
18 files changed, 263 insertions, 413 deletions
diff --git a/logd/Android.mk b/logd/Android.mk index 188511f..127a66b 100644 --- a/logd/Android.mk +++ b/logd/Android.mk @@ -26,7 +26,16 @@ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils -LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags) +# This is what we want to do: +# event_logtags = $(shell \ +# sed -n \ +# "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p" \ +# $(LOCAL_PATH)/$2/event.logtags) +# event_flag := $(call event_logtags,auditd) +# so make sure we do not regret hard-coding it as follows: +event_flag := -DAUDITD_LOG_TAG=1003 + +LOCAL_CFLAGS := -Werror $(event_flag) include $(BUILD_EXECUTABLE) diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp index d7088b4..561ea3e 100644 --- a/logd/CommandListener.cpp +++ b/logd/CommandListener.cpp @@ -44,6 +44,7 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/, registerCmd(new GetStatisticsCmd(buf)); registerCmd(new SetPruneListCmd(buf)); registerCmd(new GetPruneListCmd(buf)); + registerCmd(new ReinitCmd()); } CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader, @@ -296,6 +297,21 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli, return 0; } +CommandListener::ReinitCmd::ReinitCmd() + : LogCommand("reinit") +{ } + +int CommandListener::ReinitCmd::runCommand(SocketClient *cli, + int /*argc*/, char ** /*argv*/) { + setname(); + + reinit_signal_handler(SIGHUP); + + cli->sendMsg("success"); + + return 0; +} + int CommandListener::getLogSocket() { static const char socketName[] = "logd"; int sock = android_get_control_socket(socketName); diff --git a/logd/CommandListener.h b/logd/CommandListener.h index cd1c306..83e06b4 100644 --- a/logd/CommandListener.h +++ b/logd/CommandListener.h @@ -23,6 +23,9 @@ #include "LogReader.h" #include "LogListener.h" +// See main.cpp for implementation +void reinit_signal_handler(int /*signal*/); + class CommandListener : public FrameworkListener { LogBuffer &mBuf; @@ -60,6 +63,14 @@ private: LogBufferCmd(GetStatistics) LogBufferCmd(GetPruneList) LogBufferCmd(SetPruneList) + + class ReinitCmd : public LogCommand { + public: + ReinitCmd(); + virtual ~ReinitCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + }; #endif diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp index 3be07c0..26a1861 100644 --- a/logd/FlushCommand.cpp +++ b/logd/FlushCommand.cpp @@ -27,7 +27,7 @@ FlushCommand::FlushCommand(LogReader &reader, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start) + uint64_t start) : mReader(reader) , mNonBlock(nonBlock) , mTail(tail) diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h index f34c06a..61c6858 100644 --- a/logd/FlushCommand.h +++ b/logd/FlushCommand.h @@ -31,7 +31,7 @@ class FlushCommand : public SocketClientCommand { unsigned long mTail; unsigned int mLogMask; pid_t mPid; - log_time mStart; + uint64_t mStart; public: FlushCommand(LogReader &mReader, @@ -39,7 +39,7 @@ public: unsigned long tail = -1, unsigned int logMask = -1, pid_t pid = 0, - log_time start = LogTimeEntry::EPOCH); + uint64_t start = 1); virtual void runSocketCommand(SocketClient *client); static bool hasReadLogs(SocketClient *client); diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index c7c0249..6b3e637 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -15,6 +15,7 @@ */ #include <ctype.h> +#include <endian.h> #include <errno.h> #include <limits.h> #include <stdarg.h> @@ -23,13 +24,15 @@ #include <sys/uio.h> #include <syslog.h> +#include <private/android_logger.h> + #include "libaudit.h" #include "LogAudit.h" -#define KMSG_PRIORITY(PRI) \ - '<', \ - '0' + (LOG_AUTH | (PRI)) / 10, \ - '0' + (LOG_AUTH | (PRI)) % 10, \ +#define KMSG_PRIORITY(PRI) \ + '<', \ + '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) @@ -138,29 +141,23 @@ int LogAudit::logPrint(const char *fmt, ...) { // log to events size_t l = strlen(str); - size_t n = l + sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t); + size_t n = l + sizeof(android_log_event_string_t); bool notify = false; - char *newstr = reinterpret_cast<char *>(malloc(n)); - if (!newstr) { + android_log_event_string_t *event = static_cast<android_log_event_string_t *>(malloc(n)); + if (!event) { rc = -ENOMEM; } else { - cp = newstr; - *cp++ = AUDITD_LOG_TAG & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 8) & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 16) & 0xFF; - *cp++ = (AUDITD_LOG_TAG >> 24) & 0xFF; - *cp++ = EVENT_TYPE_STRING; - *cp++ = l & 0xFF; - *cp++ = (l >> 8) & 0xFF; - *cp++ = (l >> 16) & 0xFF; - *cp++ = (l >> 24) & 0xFF; - memcpy(cp, str, l); - - logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, newstr, + event->header.tag = htole32(AUDITD_LOG_TAG); + event->payload.type = EVENT_TYPE_STRING; + event->payload.length = htole32(l); + memcpy(event->payload.data, str, l); + + logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid, + reinterpret_cast<char *>(event), (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX); - free(newstr); + free(event); notify = true; } @@ -190,7 +187,7 @@ int LogAudit::logPrint(const char *fmt, ...) { } n = (estr - str) + strlen(ecomm) + l + 2; - newstr = reinterpret_cast<char *>(malloc(n)); + char *newstr = static_cast<char *>(malloc(n)); if (!newstr) { rc = -ENOMEM; } else { diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 3d0b38f..2693583 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -92,11 +92,7 @@ static unsigned long property_get_size(const char *key) { return value; } -LogBuffer::LogBuffer(LastLogTimes *times) - : dgramQlenStatistics(false) - , mTimes(*times) { - pthread_mutex_init(&mLogElementsLock, NULL); - +void LogBuffer::init() { static const char global_tuneable[] = "persist.logd.size"; // Settings App static const char global_default[] = "ro.logd.size"; // BoardConfig.mk @@ -132,6 +128,13 @@ LogBuffer::LogBuffer(LastLogTimes *times) } } +LogBuffer::LogBuffer(LastLogTimes *times) + : mTimes(*times) { + pthread_mutex_init(&mLogElementsLock, NULL); + + init(); +} + void LogBuffer::log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char *msg, unsigned short len) { @@ -150,23 +153,6 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, while (last != mLogElements.begin()) { --it; if ((*it)->getRealTime() <= realtime) { - // halves the peak performance, use with caution - if (dgramQlenStatistics) { - LogBufferElementCollection::iterator ib = it; - unsigned short buckets, num = 1; - for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) { - buckets -= num; - num += buckets; - while (buckets && (--ib != mLogElements.begin())) { - --buckets; - } - if (buckets) { - break; - } - stats.recordDiff( - elem->getRealTime() - (*ib)->getRealTime(), i); - } - } break; } last = it; @@ -175,7 +161,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, if (last == mLogElements.end()) { mLogElements.push_back(elem); } else { - log_time end = log_time::EPOCH; + uint64_t end = 1; bool end_set = false; bool end_always = false; @@ -198,7 +184,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime, } if (end_always - || (end_set && (end >= (*last)->getMonotonicTime()))) { + || (end_set && (end >= (*last)->getSequence()))) { mLogElements.push_back(elem); } else { mLogElements.insert(last,elem); @@ -255,7 +241,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { for(it = mLogElements.begin(); it != mLogElements.end();) { LogBufferElement *e = *it; - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { break; } @@ -307,7 +293,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { for(it = mLogElements.begin(); it != mLogElements.end();) { LogBufferElement *e = *it; - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { break; } @@ -348,7 +334,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { while((pruneRows > 0) && (it != mLogElements.end())) { LogBufferElement *e = *it; if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { if (!whitelist) { if (stats.sizes(id) > (2 * log_buffer_size(id))) { // kick a misbehaving log reader client off the island @@ -380,7 +366,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { while((it != mLogElements.end()) && (pruneRows > 0)) { LogBufferElement *e = *it; if (e->getLogId() == id) { - if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + if (oldest && (oldest->mStart <= e->getSequence())) { if (stats.sizes(id) > (2 * log_buffer_size(id))) { // kick a misbehaving log reader client off the island oldest->release_Locked(); @@ -437,16 +423,16 @@ unsigned long LogBuffer::getSize(log_id_t id) { return retval; } -log_time LogBuffer::flushTo( - SocketClient *reader, const log_time start, bool privileged, - bool (*filter)(const LogBufferElement *element, void *arg), void *arg) { +uint64_t LogBuffer::flushTo( + SocketClient *reader, const uint64_t start, bool privileged, + int (*filter)(const LogBufferElement *element, void *arg), void *arg) { LogBufferElementCollection::iterator it; - log_time max = start; + uint64_t max = start; uid_t uid = reader->getUid(); pthread_mutex_lock(&mLogElementsLock); - if (start == LogTimeEntry::EPOCH) { + if (start <= 1) { // client wants to start from the beginning it = mLogElements.begin(); } else { @@ -455,7 +441,7 @@ log_time LogBuffer::flushTo( for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) { --it; LogBufferElement *element = *it; - if (element->getMonotonicTime() <= start) { + if (element->getSequence() <= start) { it++; break; } @@ -469,13 +455,19 @@ log_time LogBuffer::flushTo( continue; } - if (element->getMonotonicTime() <= start) { + if (element->getSequence() <= start) { continue; } // NB: calling out to another object with mLogElementsLock held (safe) - if (filter && !(*filter)(element, arg)) { - continue; + if (filter) { + int ret = (*filter)(element, arg); + if (ret == false) { + continue; + } + if (ret != true) { + break; + } } pthread_mutex_unlock(&mLogElementsLock); @@ -495,7 +487,7 @@ log_time LogBuffer::flushTo( } void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) { - log_time oldest(CLOCK_MONOTONIC); + uint64_t oldest = UINT64_MAX; pthread_mutex_lock(&mLogElementsLock); @@ -505,7 +497,7 @@ void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) { LogBufferElement *element = *it; if ((logMask & (1 << element->getLogId()))) { - oldest = element->getMonotonicTime(); + oldest = element->getSequence(); break; } } diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 879baea..13e6aa8 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -37,7 +37,6 @@ class LogBuffer { pthread_mutex_t mLogElementsLock; LogStatistics stats; - bool dgramQlenStatistics; PruneList mPrune; @@ -47,13 +46,14 @@ public: LastLogTimes &mTimes; LogBuffer(LastLogTimes *times); + void init(); void log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char *msg, unsigned short len); - log_time flushTo(SocketClient *writer, const log_time start, + uint64_t flushTo(SocketClient *writer, const uint64_t start, bool privileged, - bool (*filter)(const LogBufferElement *element, void *arg) = NULL, + int (*filter)(const LogBufferElement *element, void *arg) = NULL, void *arg = NULL); void clear(log_id_t id, uid_t uid = AID_ROOT); @@ -63,11 +63,6 @@ public: // *strp uses malloc, use free to release. void formatStatistics(char **strp, uid_t uid, unsigned int logMask); - void enableDgramQlenStatistics() { - stats.enableDgramQlenStatistics(); - dgramQlenStatistics = true; - } - void enableStatistics() { stats.enableStatistics(); } diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index d959ceb..5e780b5 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -24,7 +24,8 @@ #include "LogBufferElement.h" #include "LogReader.h" -const log_time LogBufferElement::FLUSH_ERROR((uint32_t)0, (uint32_t)0); +const uint64_t LogBufferElement::FLUSH_ERROR(0); +atomic_int_fast64_t LogBufferElement::sequence; LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, @@ -34,7 +35,7 @@ LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, , mPid(pid) , mTid(tid) , mMsgLen(len) - , mMonotonicTime(CLOCK_MONOTONIC) + , mSequence(sequence.fetch_add(1, memory_order_relaxed)) , mRealTime(realtime) { mMsg = new char[len]; memcpy(mMsg, msg, len); @@ -44,7 +45,7 @@ LogBufferElement::~LogBufferElement() { delete [] mMsg; } -log_time LogBufferElement::flushTo(SocketClient *reader) { +uint64_t LogBufferElement::flushTo(SocketClient *reader) { struct logger_entry_v3 entry; memset(&entry, 0, sizeof(struct logger_entry_v3)); entry.hdr_size = sizeof(struct logger_entry_v3); @@ -64,5 +65,5 @@ log_time LogBufferElement::flushTo(SocketClient *reader) { return FLUSH_ERROR; } - return mMonotonicTime; + return mSequence; } diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index fdca973..25f1450 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -18,6 +18,7 @@ #define _LOGD_LOG_BUFFER_ELEMENT_H__ #include <sys/types.h> +#include <stdatomic.h> #include <sysutils/SocketClient.h> #include <log/log.h> #include <log/log_read.h> @@ -29,8 +30,9 @@ class LogBufferElement { const pid_t mTid; char *mMsg; const unsigned short mMsgLen; - const log_time mMonotonicTime; + const uint64_t mSequence; const log_time mRealTime; + static atomic_int_fast64_t sequence; public: LogBufferElement(log_id_t log_id, log_time realtime, @@ -43,11 +45,12 @@ public: pid_t getPid(void) const { return mPid; } pid_t getTid(void) const { return mTid; } unsigned short getMsgLen() const { return mMsgLen; } - log_time getMonotonicTime(void) const { return mMonotonicTime; } + uint64_t getSequence(void) const { return mSequence; } + static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); } log_time getRealTime(void) const { return mRealTime; } - static const log_time FLUSH_ERROR; - log_time flushTo(SocketClient *writer); + static const uint64_t FLUSH_ERROR; + uint64_t flushTo(SocketClient *writer); }; #endif diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp index 26df087..f7df275 100644 --- a/logd/LogReader.cpp +++ b/logd/LogReader.cpp @@ -100,50 +100,51 @@ bool LogReader::onDataAvailable(SocketClient *cli) { nonBlock = true; } - // Convert realtime to monotonic time - if (start == log_time::EPOCH) { - start = LogTimeEntry::EPOCH; - } else { + uint64_t sequence = 1; + // Convert realtime to sequence number + if (start != log_time::EPOCH) { class LogFindStart { const pid_t mPid; const unsigned mLogMask; bool startTimeSet; log_time &start; - log_time last; + uint64_t &sequence; + uint64_t last; public: - LogFindStart(unsigned logMask, pid_t pid, log_time &start) + LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) : mPid(pid) , mLogMask(logMask) , startTimeSet(false) , start(start) - , last(LogTimeEntry::EPOCH) + , sequence(sequence) + , last(sequence) { } - static bool callback(const LogBufferElement *element, void *obj) { + static int callback(const LogBufferElement *element, void *obj) { LogFindStart *me = reinterpret_cast<LogFindStart *>(obj); - if (!me->startTimeSet - && (!me->mPid || (me->mPid == element->getPid())) + if ((!me->mPid || (me->mPid == element->getPid())) && (me->mLogMask & (1 << element->getLogId()))) { if (me->start == element->getRealTime()) { - me->start = element->getMonotonicTime(); + me->sequence = element->getSequence(); me->startTimeSet = true; + return -1; } else { if (me->start < element->getRealTime()) { - me->start = me->last; + me->sequence = me->last; me->startTimeSet = true; + return -1; } - me->last = element->getMonotonicTime(); + me->last = element->getSequence(); } } return false; } bool found() { return startTimeSet; } - } logFindStart(logMask, pid, start); + } logFindStart(logMask, pid, start, sequence); - logbuf().flushTo(cli, LogTimeEntry::EPOCH, - FlushCommand::hasReadLogs(cli), + logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli), logFindStart.callback, &logFindStart); if (!logFindStart.found()) { @@ -151,12 +152,11 @@ bool LogReader::onDataAvailable(SocketClient *cli) { doSocketDelete(cli); return false; } - log_time now(CLOCK_MONOTONIC); - start = now; + sequence = LogBufferElement::getCurrentSequence(); } } - FlushCommand command(*this, nonBlock, tail, logMask, pid, start); + FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence); command.runSocketCommand(cli); return true; } diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 53036e6..5a70689 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -395,71 +395,11 @@ size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) { LogStatistics::LogStatistics() : mStatistics(false) - , dgramQlenStatistics(false) , start(CLOCK_MONOTONIC) { log_id_for_each(i) { mSizes[i] = 0; mElements[i] = 0; } - - for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) { - mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max; - mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max; - } -} - -// Each bucket below represents a dgramQlen of log messages. By -// finding the minimum period of time from start to finish -// of each dgramQlen, we can get a performance expectation for -// the user space logger. The net result is that the period -// of time divided by the dgramQlen will give us the average time -// between log messages; at the point where the average time -// is greater than the throughput capability of the logger -// we will not longer require the benefits of the FIFO formed -// by max_dgram_qlen. We will also expect to see a very visible -// knee in the average time between log messages at this point, -// so we do not necessarily have to compare the rate against the -// measured performance (BM_log_maximum_retry) of the logger. -// -// for example (reformatted): -// -// Minimum time between log events per dgramQlen: -// 1 2 3 5 10 20 30 50 100 200 300 400 500 600 -// 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5 -// -// demonstrates a clear knee rising at 100, so this means that for this -// case max_dgram_qlen = 100 would be more than sufficient to handle the -// worst that the system could stuff into the logger. The -// BM_log_maximum_retry performance (derated by the log collection) on the -// same system was 33.2us so we would almost be fine with max_dgram_qlen = 50. -// BM_log_maxumum_retry with statistics off is roughly 20us, so -// max_dgram_qlen = 20 would work. We will be more than willing to have -// a large engineering margin so the rule of thumb that lead us to 100 is -// fine. -// -// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 -const unsigned short LogStatistics::mBuckets[] = { - 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600 -}; - -unsigned short LogStatistics::dgramQlen(unsigned short bucket) { - if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) { - return 0; - } - return mBuckets[bucket]; -} - -unsigned long long LogStatistics::minimum(unsigned short bucket) { - if (mMinimum[bucket].tv_sec == mMinimum[bucket].tv_sec_max) { - return 0; - } - return mMinimum[bucket].nsec(); -} - -void LogStatistics::recordDiff(log_time diff, unsigned short bucket) { - if ((diff.tv_sec || diff.tv_nsec) && (mMinimum[bucket] > diff)) { - mMinimum[bucket] = diff; - } } void LogStatistics::add(unsigned short size, @@ -709,55 +649,6 @@ void LogStatistics::format(char **buf, pids.clear(); } - if (dgramQlenStatistics) { - const unsigned short spaces_time = 6; - const unsigned long long max_seconds = 100000; - spaces = 0; - string.append("\n\nMinimum time between log events per max_dgram_qlen:\n"); - for(unsigned short i = 0; dgramQlen(i); ++i) { - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%u", spaces, "", dgramQlen(i)); - spaces += spaces_time + oldLength - string.length(); - } - string.append("\n"); - spaces = 0; - unsigned short n; - for(unsigned short i = 0; (n = dgramQlen(i)); ++i) { - unsigned long long duration = minimum(i); - if (duration) { - duration /= n; - if (duration >= (NS_PER_SEC * max_seconds)) { - duration = NS_PER_SEC * (max_seconds - 1); - } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s", spaces, ""); - if (duration >= (NS_PER_SEC * 10)) { - string.appendFormat("%llu", - (duration + (NS_PER_SEC / 2)) - / NS_PER_SEC); - } else if (duration >= (NS_PER_SEC / (1000 / 10))) { - string.appendFormat("%llum", - (duration + (NS_PER_SEC / 2 / 1000)) - / (NS_PER_SEC / 1000)); - } else if (duration >= (NS_PER_SEC / (1000000 / 10))) { - string.appendFormat("%lluu", - (duration + (NS_PER_SEC / 2 / 1000000)) - / (NS_PER_SEC / 1000000)); - } else { - string.appendFormat("%llun", duration); - } - spaces -= string.length() - oldLength; - } - spaces += spaces_time; - } - } - log_id_for_each(i) { if (!(logMask & (1 << i))) { continue; diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index f6c4329..f892cd0 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -145,7 +145,6 @@ class LogStatistics { size_t mElements[LOG_ID_MAX]; bool mStatistics; - bool dgramQlenStatistics; static const unsigned short mBuckets[14]; log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])]; @@ -157,11 +156,7 @@ public: LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; } - void enableDgramQlenStatistics() { dgramQlenStatistics = true; } void enableStatistics() { mStatistics = true; } - static unsigned short dgramQlen(unsigned short bucket); - unsigned long long minimum(unsigned short bucket); - void recordDiff(log_time diff, unsigned short bucket); void add(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); void subtract(unsigned short size, log_id_t log_id, uid_t uid, pid_t pid); diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp index 5f9db8d..1b60b7e 100644 --- a/logd/LogTimes.cpp +++ b/logd/LogTimes.cpp @@ -23,12 +23,10 @@ pthread_mutex_t LogTimeEntry::timesLock = PTHREAD_MUTEX_INITIALIZER; -const struct timespec LogTimeEntry::EPOCH = { 0, 1 }; - LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start) + uint64_t start) : mRefCount(1) , mRelease(false) , mError(false) @@ -42,7 +40,7 @@ LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client, , mClient(client) , mStart(start) , mNonBlock(nonBlock) - , mEnd(CLOCK_MONOTONIC) + , mEnd(LogBufferElement::getCurrentSequence()) { pthread_cond_init(&threadTriggeredCondition, NULL); cleanSkip_Locked(); @@ -129,7 +127,7 @@ void *LogTimeEntry::threadStart(void *obj) { lock(); while (me->threadRunning && !me->isError_Locked()) { - log_time start = me->mStart; + uint64_t start = me->mStart; unlock(); @@ -161,13 +159,13 @@ void *LogTimeEntry::threadStart(void *obj) { } // A first pass to count the number of elements -bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { +int LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); if (me->mCount == 0) { - me->mStart = element->getMonotonicTime(); + me->mStart = element->getSequence(); } if ((!me->mPid || (me->mPid == element->getPid())) @@ -181,12 +179,12 @@ bool LogTimeEntry::FilterFirstPass(const LogBufferElement *element, void *obj) { } // A second pass to send the selected elements -bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { +int LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) { LogTimeEntry *me = reinterpret_cast<LogTimeEntry *>(obj); LogTimeEntry::lock(); - me->mStart = element->getMonotonicTime(); + me->mStart = element->getSequence(); if (me->skipAhead[element->getLogId()]) { me->skipAhead[element->getLogId()]--; @@ -195,7 +193,7 @@ bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) // Truncate to close race between first and second pass if (me->mNonBlock && me->mTail && (me->mIndex >= me->mCount)) { - goto skip; + goto stop; } if (!me->isWatching(element->getLogId())) { @@ -207,7 +205,7 @@ bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) } if (me->isError_Locked()) { - goto skip; + goto stop; } if (!me->mTail) { @@ -234,6 +232,10 @@ ok: skip: LogTimeEntry::unlock(); return false; + +stop: + LogTimeEntry::unlock(); + return -1; } void LogTimeEntry::cleanSkip_Locked(void) { diff --git a/logd/LogTimes.h b/logd/LogTimes.h index 81aedfb..ae2f92b 100644 --- a/logd/LogTimes.h +++ b/logd/LogTimes.h @@ -47,13 +47,12 @@ class LogTimeEntry { public: LogTimeEntry(LogReader &reader, SocketClient *client, bool nonBlock, unsigned long tail, unsigned int logMask, pid_t pid, - log_time start); + uint64_t start); SocketClient *mClient; - static const struct timespec EPOCH; - log_time mStart; + uint64_t mStart; const bool mNonBlock; - const log_time mEnd; // only relevant if mNonBlock + const uint64_t mEnd; // only relevant if mNonBlock // Protect List manipulations static void lock(void) { pthread_mutex_lock(×Lock); } @@ -103,8 +102,8 @@ public: } bool isWatching(log_id_t id) { return (mLogMask & (1<<id)) != 0; } // flushTo filter callbacks - static bool FilterFirstPass(const LogBufferElement *element, void *me); - static bool FilterSecondPass(const LogBufferElement *element, void *me); + static int FilterFirstPass(const LogBufferElement *element, void *me); + static int FilterSecondPass(const LogBufferElement *element, void *me); }; typedef android::List<LogTimeEntry *> LastLogTimes; diff --git a/logd/README.property b/logd/README.property index b7fcece..60542b2 100644 --- a/logd/README.property +++ b/logd/README.property @@ -7,12 +7,6 @@ logd.auditd.dmesg bool true selinux audit messages duplicated and logd.statistics bool depends Enable logcat -S statistics. ro.config.low_ram bool false if true, logd.statistics default false ro.build.type string if user, logd.statistics default false -logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This - represents a performance impact and - is used to determine the platform's - minimum domain socket network FIFO - size (see source for details) based - on typical load (logcat -S to view) persist.logd.size number 256K default size of the buffer for all log ids at initial startup, at runtime use: logcat -b all -G <value> diff --git a/logd/main.cpp b/logd/main.cpp index 7a1ae54..a61beff 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -17,7 +17,10 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> +#include <poll.h> #include <sched.h> +#include <semaphore.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -26,10 +29,12 @@ #include <sys/prctl.h> #include <sys/stat.h> #include <sys/types.h> +#include <syslog.h> #include <unistd.h> #include <cutils/properties.h> #include <cutils/sched_policy.h> +#include <cutils/sockets.h> #include "private/android_filesystem_config.h" #include "CommandListener.h" @@ -37,6 +42,12 @@ #include "LogListener.h" #include "LogAudit.h" +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \ + '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, \ + '>' + // // The service is designed to be run by init, it does not respond well // to starting up manually. When starting up manually the sockets will @@ -127,17 +138,107 @@ static bool property_get_bool(const char *key, bool def) { return def; } -// Foreground waits for exit of the three main persistent threads that -// are started here. The three threads are created to manage UNIX -// domain client sockets for writing, reading and controlling the user -// space logger. Additional transitory per-client threads are created -// for each reader once they register. -int main() { - bool auditd = property_get_bool("logd.auditd", true); +// Remove the static, and use this variable +// globally for debugging if necessary. eg: +// write(fdDmesg, "I am here\n", 10); +static int fdDmesg = -1; + +static sem_t reinit; +static bool reinit_running = false; +static LogBuffer *logBuf = NULL; + +static void *reinit_thread_start(void * /*obj*/) { + prctl(PR_SET_NAME, "logd.daemon"); + set_sched_policy(0, SP_BACKGROUND); + + setgid(AID_LOGD); + setuid(AID_LOGD); + + while (reinit_running && !sem_wait(&reinit) && reinit_running) { + if (fdDmesg >= 0) { + static const char reinit_message[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'd', 'a', 'e', 'm', 'o', 'n', ':', + ' ', 'r', 'e', 'i', 'n', 'i', 't', '\n' }; + write(fdDmesg, reinit_message, sizeof(reinit_message)); + } + + // Anything that reads persist.<property> + if (logBuf) { + logBuf->init(); + } + } + + return NULL; +} + +// Serves as a global method to trigger reinitialization +// and as a function that can be provided to signal(). +void reinit_signal_handler(int /*signal*/) { + sem_post(&reinit); +} + +// Foreground waits for exit of the main persistent threads +// that are started here. The threads are created to manage +// UNIX domain client sockets for writing, reading and +// controlling the user space logger, and for any additional +// logging plugins like auditd and restart control. Additional +// transitory per-client threads are created for each reader. +int main(int argc, char *argv[]) { + fdDmesg = open("/dev/kmsg", O_WRONLY); + + // issue reinit command. KISS argument parsing. + if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) { + int sock = TEMP_FAILURE_RETRY( + socket_local_client("logd", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)); + if (sock < 0) { + return -errno; + } + static const char reinit[] = "reinit"; + ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinit, sizeof(reinit))); + if (ret < 0) { + return -errno; + } + struct pollfd p; + memset(&p, 0, sizeof(p)); + p.fd = sock; + p.events = POLLIN; + ret = TEMP_FAILURE_RETRY(poll(&p, 1, 100)); + if (ret < 0) { + return -errno; + } + if ((ret == 0) || !(p.revents & POLLIN)) { + return -ETIME; + } + static const char success[] = "success"; + char buffer[sizeof(success) - 1]; + memset(buffer, 0, sizeof(buffer)); + ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer))); + if (ret < 0) { + return -errno; + } + return strncmp(buffer, success, sizeof(success) - 1) != 0; + } - int fdDmesg = -1; - if (auditd && property_get_bool("logd.auditd.dmesg", true)) { - fdDmesg = open("/dev/kmsg", O_WRONLY); + // Reinit Thread + sem_init(&reinit, 0, 0); + pthread_attr_t attr; + if (!pthread_attr_init(&attr)) { + struct sched_param param; + + memset(¶m, 0, sizeof(param)); + pthread_attr_setschedparam(&attr, ¶m); + pthread_attr_setschedpolicy(&attr, SCHED_BATCH); + if (!pthread_attr_setdetachstate(&attr, + PTHREAD_CREATE_DETACHED)) { + pthread_t thread; + reinit_running = true; + if (pthread_create(&thread, &attr, reinit_thread_start, NULL)) { + reinit_running = false; + } + } + pthread_attr_destroy(&attr); } if (drop_privs() != 0) { @@ -153,11 +254,10 @@ int main() { // LogBuffer is the object which is responsible for holding all // log entries. - LogBuffer *logBuf = new LogBuffer(times); + logBuf = new LogBuffer(times); + + signal(SIGHUP, reinit_signal_handler); - if (property_get_bool("logd.statistics.dgram_qlen", false)) { - logBuf->enableDgramQlenStatistics(); - } { char property[PROPERTY_VALUE_MAX]; property_get("ro.build.type", property, ""); @@ -198,9 +298,13 @@ int main() { // initiated log messages. New log entries are added to LogBuffer // and LogReader is notified to send updates to connected clients. + bool auditd = property_get_bool("logd.auditd", true); + if (auditd) { + bool dmesg = property_get_bool("logd.auditd.dmesg", true); + // failure is an option ... messages are in dmesg (required by standard) - LogAudit *al = new LogAudit(logBuf, reader, fdDmesg); + LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1); int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0); if (len > 0) { @@ -220,11 +324,10 @@ int main() { if (al->startListener()) { delete al; - close(fdDmesg); } } - pause(); + TEMP_FAILURE_RETRY(pause()); + exit(0); } - diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp index 96877a9..46bd9c0 100644 --- a/logd/tests/logd_test.cpp +++ b/logd/tests/logd_test.cpp @@ -192,164 +192,6 @@ TEST(logd, statistics) { EXPECT_TRUE(NULL != events_logs); #endif - // Parse timing stats - - cp = strstr(cp, "Minimum time between log events per dgram_qlen:"); - - if (cp) { - while (*cp && (*cp != '\n')) { - ++cp; - } - if (*cp == '\n') { - ++cp; - } - - char *list_of_spans = cp; - EXPECT_NE('\0', *list_of_spans); - - unsigned short number_of_buckets = 0; - unsigned short *dgram_qlen = NULL; - unsigned short bucket = 0; - while (*cp && (*cp != '\n')) { - bucket = 0; - while (isdigit(*cp)) { - bucket = bucket * 10 + *cp - '0'; - ++cp; - } - while (*cp == ' ') { - ++cp; - } - if (!bucket) { - break; - } - unsigned short *new_dgram_qlen = new unsigned short[number_of_buckets + 1]; - EXPECT_TRUE(new_dgram_qlen != NULL); - if (dgram_qlen) { - memcpy(new_dgram_qlen, dgram_qlen, sizeof(*dgram_qlen) * number_of_buckets); - delete [] dgram_qlen; - } - - dgram_qlen = new_dgram_qlen; - dgram_qlen[number_of_buckets++] = bucket; - } - - char *end_of_spans = cp; - EXPECT_NE('\0', *end_of_spans); - - EXPECT_LT(5, number_of_buckets); - - unsigned long long *times = new unsigned long long [number_of_buckets]; - ASSERT_TRUE(times != NULL); - - memset(times, 0, sizeof(*times) * number_of_buckets); - - while (*cp == '\n') { - ++cp; - } - - unsigned short number_of_values = 0; - unsigned long long value; - while (*cp && (*cp != '\n')) { - EXPECT_GE(number_of_buckets, number_of_values); - - value = 0; - while (isdigit(*cp)) { - value = value * 10ULL + *cp - '0'; - ++cp; - } - - switch(*cp) { - case ' ': - case '\n': - value *= 1000ULL; - /* FALLTHRU */ - case 'm': - value *= 1000ULL; - /* FALLTHRU */ - case 'u': - value *= 1000ULL; - /* FALLTHRU */ - case 'n': - default: - break; - } - while (*++cp == ' '); - - if (!value) { - break; - } - - times[number_of_values] = value; - ++number_of_values; - } - -#ifdef TARGET_USES_LOGD - EXPECT_EQ(number_of_values, number_of_buckets); -#endif - - FILE *fp; - ASSERT_TRUE(NULL != (fp = fopen("/proc/sys/net/unix/max_dgram_qlen", "r"))); - - unsigned max_dgram_qlen = 0; - fscanf(fp, "%u", &max_dgram_qlen); - - fclose(fp); - - // Find launch point - unsigned short launch = 0; - unsigned long long total = 0; - do { - total += times[launch]; - } while (((++launch < number_of_buckets) - && ((total / launch) >= (times[launch] / 8ULL))) - || (launch == 1)); // too soon - - bool failure = number_of_buckets <= launch; - if (!failure) { - unsigned short l = launch; - if (l >= number_of_buckets) { - l = number_of_buckets - 1; - } - failure = max_dgram_qlen < dgram_qlen[l]; - } - - // We can get failure if at any time liblog_benchmarks has been run - // because designed to overload /proc/sys/net/unix/max_dgram_qlen even - // at excessive values like 20000. It does so to measure the raw processing - // performance of logd. - if (failure) { - cp = find_benchmark_spam(cp); - } - - if (cp) { - // Fake a failure, but without the failure code - if (number_of_buckets <= launch) { - printf ("Expected: number_of_buckets > launch, actual: %u vs %u\n", - number_of_buckets, launch); - } - if (launch >= number_of_buckets) { - launch = number_of_buckets - 1; - } - if (max_dgram_qlen < dgram_qlen[launch]) { - printf ("Expected: max_dgram_qlen >= dgram_qlen[%d]," - " actual: %u vs %u\n", - launch, max_dgram_qlen, dgram_qlen[launch]); - } - } else -#ifndef TARGET_USES_LOGD - if (total) -#endif - { - EXPECT_GT(number_of_buckets, launch); - if (launch >= number_of_buckets) { - launch = number_of_buckets - 1; - } - EXPECT_GE(max_dgram_qlen, dgram_qlen[launch]); - } - - delete [] dgram_qlen; - delete [] times; - } delete [] buf; } |