diff options
Diffstat (limited to 'logd')
-rw-r--r-- | logd/LogBuffer.cpp | 38 | ||||
-rw-r--r-- | logd/LogBuffer.h | 1 | ||||
-rw-r--r-- | logd/LogBufferElement.cpp | 104 | ||||
-rw-r--r-- | logd/LogBufferElement.h | 11 | ||||
-rw-r--r-- | logd/main.cpp | 13 |
5 files changed, 140 insertions, 27 deletions
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 1859461c2..b6b612468 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -247,7 +247,7 @@ public: uint64_t getKey() { return value; } }; -struct LogBufferElementEntry { +class LogBufferElementEntry { const uint64_t key; LogBufferElement *last; @@ -259,8 +259,9 @@ public: LogBufferElement *getLast() { return last; } }; -struct LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> { +class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> { +public: bool merge(LogBufferElement *e, unsigned short dropped) { LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid()); android::hash_t hash = android::hash_type(key.getKey()); @@ -286,6 +287,22 @@ struct LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBuffer add(hash, LogBufferElementEntry(key.getKey(), e)); } + inline void clear() { + android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear(); + } + + void clear(LogBufferElement *e) { + uint64_t current = e->getRealTime().nsec() - NS_PER_SEC; + ssize_t index = -1; + while((index = next(index)) >= 0) { + LogBufferElement *l = editEntryAt(index).getLast(); + if ((l->getDropped() >= 4) && (current > l->getRealTime().nsec())) { + removeAt(index); + index = -1; + } + } + } + }; // prune "pruneRows" of type "id" from the buffer. @@ -349,9 +366,16 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { if (sorted.get()) { if (sorted[0] && sorted[1]) { - worst = sorted[0]->getKey(); worst_sizes = sorted[0]->getSizes(); - second_worst_sizes = sorted[1]->getSizes(); + // Calculate threshold as 12.5% of available storage + size_t threshold = log_buffer_size(id) / 8; + if (worst_sizes > threshold) { + worst = sorted[0]->getKey(); + second_worst_sizes = sorted[1]->getSizes(); + if (second_worst_sizes < threshold) { + second_worst_sizes = threshold; + } + } } } } @@ -395,7 +419,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { leading = false; if (hasBlacklist && mPrune.naughty(e)) { - last.clear(); + last.clear(e); it = erase(it); if (dropped) { continue; @@ -423,7 +447,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { } if (e->getUid() != worst) { - last.clear(); + last.clear(e); ++it; continue; } @@ -607,7 +631,7 @@ uint64_t LogBuffer::flushTo( pthread_mutex_unlock(&mLogElementsLock); // range locking in LastLogTimes looks after us - max = element->flushTo(reader); + max = element->flushTo(reader, this); if (max == element->FLUSH_ERROR) { return max; diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 9ee243d31..00b19b67b 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -74,6 +74,7 @@ public: // helper char *pidToName(pid_t pid) { return stats.pidToName(pid); } uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); } + char *uidToName(uid_t uid) { return stats.uidToName(uid); } private: void maybePrune(log_id_t id); diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index a173e63fe..6a057000d 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -14,7 +14,9 @@ * limitations under the License. */ +#include <ctype.h> #include <endian.h> +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <time.h> @@ -48,18 +50,88 @@ LogBufferElement::~LogBufferElement() { delete [] mMsg; } +// caller must own and free character string +static char *tidToName(pid_t tid) { + char *retval = NULL; + char buffer[256]; + snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid); + int fd = open(buffer, O_RDONLY); + if (fd >= 0) { + ssize_t ret = read(fd, buffer, sizeof(buffer)); + if (ret >= (ssize_t)sizeof(buffer)) { + ret = sizeof(buffer) - 1; + } + while ((ret > 0) && isspace(buffer[ret - 1])) { + --ret; + } + if (ret > 0) { + buffer[ret] = '\0'; + retval = strdup(buffer); + } + close(fd); + } + + // if nothing for comm, check out cmdline + char *name = android::pidToName(tid); + if (!retval) { + retval = name; + name = NULL; + } + + // check if comm is truncated, see if cmdline has full representation + if (name) { + // impossible for retval to be NULL if name not NULL + size_t retval_len = strlen(retval); + size_t name_len = strlen(name); + // KISS: ToDo: Only checks prefix truncated, not suffix, or both + if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) { + free(retval); + retval = name; + } else { + free(name); + } + } + return retval; +} + // assumption: mMsg == NULL -size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) { - static const char format_uid[] = "uid=%u dropped=%u"; - static const size_t unprivileged_offset = 7; +size_t LogBufferElement::populateDroppedMessage(char *&buffer, + LogBuffer *parent) { static const char tag[] = "logd"; + static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s"; - size_t len; - if (privileged) { - len = snprintf(NULL, 0, format_uid, mUid, mDropped); - } else { - len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped); + char *name = parent->uidToName(mUid); + char *commName = tidToName(mTid); + if (!commName && (mTid != mPid)) { + commName = tidToName(mPid); + } + if (!commName) { + commName = parent->pidToName(mPid); + } + if (name && commName && !strcmp(name, commName)) { + free(commName); + commName = NULL; + } + if (name) { + char *p = NULL; + asprintf(&p, "(%s)", name); + if (p) { + free(name); + name = p; + } + } + if (commName) { + char *p = NULL; + asprintf(&p, " comm=%s", commName); + if (p) { + free(commName); + commName = p; + } } + // identical to below to calculate the buffer size required + size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "", + commName ? commName : "", + mDropped, (mDropped > 1) ? "s" : ""); size_t hdrLen; if (mLogId == LOG_ID_EVENTS) { @@ -70,6 +142,8 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) buffer = static_cast<char *>(calloc(1, hdrLen + len + 1)); if (!buffer) { + free(name); + free(commName); return 0; } @@ -86,16 +160,16 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) strcpy(buffer + 1, tag); } - if (privileged) { - snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped); - } else { - snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped); - } + snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "", + commName ? commName : "", + mDropped, (mDropped > 1) ? "s" : ""); + free(name); + free(commName); return retval; } -uint64_t LogBufferElement::flushTo(SocketClient *reader) { +uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) { struct logger_entry_v3 entry; memset(&entry, 0, sizeof(struct logger_entry_v3)); @@ -114,7 +188,7 @@ uint64_t LogBufferElement::flushTo(SocketClient *reader) { char *buffer = NULL; if (!mMsg) { - entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader)); + entry.len = populateDroppedMessage(buffer, parent); if (!entry.len) { return mSequence; } diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h index 6c08811fb..b6c6196d2 100644 --- a/logd/LogBufferElement.h +++ b/logd/LogBufferElement.h @@ -31,15 +31,19 @@ namespace android { // Furnished in main.cpp. Caller must own and free returned value -// This function is designed for a single caller and is NOT thread-safe char *uidToName(uid_t uid); +// Furnished in LogStatistics.cpp. Caller must own and free returned value +char *pidToName(pid_t pid); + } static inline bool worstUidEnabledForLogid(log_id_t id) { return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS); } +class LogBuffer; + class LogBufferElement { const log_id_t mLogId; const uid_t mUid; @@ -55,7 +59,8 @@ class LogBufferElement { static atomic_int_fast64_t sequence; // assumption: mMsg == NULL - size_t populateDroppedMessage(char *&buffer, bool privileged); + size_t populateDroppedMessage(char *&buffer, + LogBuffer *parent); public: LogBufferElement(log_id_t log_id, log_time realtime, @@ -81,7 +86,7 @@ public: log_time getRealTime(void) const { return mRealTime; } static const uint64_t FLUSH_ERROR; - uint64_t flushTo(SocketClient *writer); + uint64_t flushTo(SocketClient *writer, LogBuffer *parent); }; #endif diff --git a/logd/main.cpp b/logd/main.cpp index eb29596ec..237c7c1cf 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -210,18 +210,26 @@ static void *reinit_thread_start(void * /*obj*/) { return NULL; } +static sem_t sem_name; + char *android::uidToName(uid_t u) { if (!u || !reinit_running) { return NULL; } - // Not multi-thread safe, we know there is only one caller + sem_wait(&sem_name); + + // Not multi-thread safe, we use sem_name to protect uid = u; name = NULL; sem_post(&reinit); sem_wait(&uidName); - return name; + char *ret = name; + + sem_post(&sem_name); + + return ret; } // Serves as a global method to trigger reinitialization @@ -277,6 +285,7 @@ int main(int argc, char *argv[]) { // Reinit Thread sem_init(&reinit, 0, 0); sem_init(&uidName, 0, 0); + sem_init(&sem_name, 0, 1); pthread_attr_t attr; if (!pthread_attr_init(&attr)) { struct sched_param param; |