diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index 808d17a66..2f7cbfb1a 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -183,7 +183,7 @@ int LogAudit::logPrint(const char *fmt, ...) { static const char comm_str[] = " comm=\""; const char *comm = strstr(str, comm_str); const char *estr = str + strlen(str); - char *commfree = NULL; + const char *commfree = NULL; if (comm) { estr = comm; comm += sizeof(comm_str) - 1; @@ -231,7 +231,7 @@ int LogAudit::logPrint(const char *fmt, ...) { // end scope for main buffer } - free(commfree); + free(const_cast(commfree)); free(str); if (notify) { diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index d8e0b90f2..371c79698 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -78,9 +78,9 @@ public: std::string formatPrune() { return mPrune.format(); } // helper must be protected directly or implicitly by lock()/unlock() - char *pidToName(pid_t pid) { return stats.pidToName(pid); } + const 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); } + const char *uidToName(uid_t uid) { return stats.uidToName(uid); } void lock() { pthread_mutex_lock(&mLogElementsLock); } void unlock() { pthread_mutex_unlock(&mLogElementsLock); } diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp index 150ce2220..c4c302b0a 100644 --- a/logd/LogBufferElement.cpp +++ b/logd/LogBufferElement.cpp @@ -113,9 +113,9 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, static const char format_uid[] = "uid=%u%s%s expire %u line%s"; parent->lock(); - char *name = parent->uidToName(mUid); + const char *name = parent->uidToName(mUid); parent->unlock(); - char *commName = android::tidToName(mTid); + const char *commName = android::tidToName(mTid); if (!commName && (mTid != mPid)) { commName = android::tidToName(mPid); } @@ -128,28 +128,28 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, size_t len = strlen(name + 1); if (!strncmp(name + 1, commName + 1, len)) { if (commName[len + 1] == '\0') { - free(commName); + free(const_cast(commName)); commName = NULL; } else { - free(name); + free(const_cast(name)); name = NULL; } } } if (name) { - char *p = NULL; - asprintf(&p, "(%s)", name); - if (p) { - free(name); - name = p; + char *buf = NULL; + asprintf(&buf, "(%s)", name); + if (buf) { + free(const_cast(name)); + name = buf; } } if (commName) { - char *p = NULL; - asprintf(&p, " %s", commName); - if (p) { - free(commName); - commName = p; + char *buf = NULL; + asprintf(&buf, " %s", commName); + if (buf) { + free(const_cast(commName)); + commName = buf; } } // identical to below to calculate the buffer size required @@ -166,18 +166,19 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, buffer = static_cast(calloc(1, hdrLen + len + 1)); if (!buffer) { - free(name); - free(commName); + free(const_cast(name)); + free(const_cast(commName)); return 0; } size_t retval = hdrLen + len; if (mLogId == LOG_ID_EVENTS) { - android_log_event_string_t *e = reinterpret_cast(buffer); + android_log_event_string_t *event = + reinterpret_cast(buffer); - e->header.tag = htole32(LOGD_LOG_TAG); - e->type = EVENT_TYPE_STRING; - e->length = htole32(len); + event->header.tag = htole32(LOGD_LOG_TAG); + event->type = EVENT_TYPE_STRING; + event->length = htole32(len); } else { ++retval; buffer[0] = ANDROID_LOG_INFO; @@ -187,8 +188,8 @@ size_t LogBufferElement::populateDroppedMessage(char *&buffer, snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "", commName ? commName : "", mDropped, (mDropped > 1) ? "s" : ""); - free(name); - free(commName); + free(const_cast(name)); + free(const_cast(commName)); return retval; } diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index a9c30867b..c3b10ad36 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -14,15 +14,12 @@ * limitations under the License. */ -#include // std::max #include #include #include #include -#include #include -#include #include "LogStatistics.h" @@ -63,9 +60,9 @@ char *pidToName(pid_t pid) { } -void LogStatistics::add(LogBufferElement *e) { - log_id_t log_id = e->getLogId(); - unsigned short size = e->getMsgLen(); +void LogStatistics::add(LogBufferElement *element) { + log_id_t log_id = element->getLogId(); + unsigned short size = element->getMsgLen(); mSizes[log_id] += size; ++mElements[log_id]; @@ -76,24 +73,24 @@ void LogStatistics::add(LogBufferElement *e) { return; } - uidTable[log_id].add(e->getUid(), e); + uidTable[log_id].add(element->getUid(), element); if (!enable) { return; } - pidTable.add(e->getPid(), e); - tidTable.add(e->getTid(), e); + pidTable.add(element->getPid(), element); + tidTable.add(element->getTid(), element); - uint32_t tag = e->getTag(); + uint32_t tag = element->getTag(); if (tag) { - tagTable.add(tag, e); + tagTable.add(tag, element); } } -void LogStatistics::subtract(LogBufferElement *e) { - log_id_t log_id = e->getLogId(); - unsigned short size = e->getMsgLen(); +void LogStatistics::subtract(LogBufferElement *element) { + log_id_t log_id = element->getLogId(); + unsigned short size = element->getMsgLen(); mSizes[log_id] -= size; --mElements[log_id]; @@ -101,40 +98,40 @@ void LogStatistics::subtract(LogBufferElement *e) { return; } - uidTable[log_id].subtract(e->getUid(), e); + uidTable[log_id].subtract(element->getUid(), element); if (!enable) { return; } - pidTable.subtract(e->getPid(), e); - tidTable.subtract(e->getTid(), e); + pidTable.subtract(element->getPid(), element); + tidTable.subtract(element->getTid(), element); - uint32_t tag = e->getTag(); + uint32_t tag = element->getTag(); if (tag) { - tagTable.subtract(tag, e); + tagTable.subtract(tag, element); } } // Atomically set an entry to drop // entry->setDropped(1) must follow this call, caller should do this explicitly. -void LogStatistics::drop(LogBufferElement *e) { - log_id_t log_id = e->getLogId(); - unsigned short size = e->getMsgLen(); +void LogStatistics::drop(LogBufferElement *element) { + log_id_t log_id = element->getLogId(); + unsigned short size = element->getMsgLen(); mSizes[log_id] -= size; - uidTable[log_id].drop(e->getUid(), e); + uidTable[log_id].drop(element->getUid(), element); if (!enable) { return; } - pidTable.drop(e->getPid(), e); - tidTable.drop(e->getTid(), e); + pidTable.drop(element->getPid(), element); + tidTable.drop(element->getTid(), element); } // caller must own and free character string -char *LogStatistics::uidToName(uid_t uid) { +const char *LogStatistics::uidToName(uid_t uid) const { // Local hard coded favourites if (uid == AID_LOGD) { return strdup("auditd"); @@ -152,7 +149,7 @@ char *LogStatistics::uidToName(uid_t uid) { // Parse /data/system/packages.list uid_t userId = uid % AID_USER; - char *name = android::uidToName(userId); + const char *name = android::uidToName(userId); if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) { name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP)); } @@ -161,17 +158,17 @@ char *LogStatistics::uidToName(uid_t uid) { } // report uid -> pid(s) -> pidToName if unique - for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) { + for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) { const PidEntry &entry = it->second; if (entry.getUid() == uid) { - const char *n = entry.getName(); + const char *nameTmp = entry.getName(); - if (n) { + if (nameTmp) { if (!name) { - name = strdup(n); - } else if (fast(name, n)) { - free(name); + name = strdup(nameTmp); + } else if (fast(name, nameTmp)) { + free(const_cast(name)); name = NULL; break; } @@ -183,28 +180,152 @@ char *LogStatistics::uidToName(uid_t uid) { return name; } -static std::string format_line( - const std::string &name, - const std::string &size, - const std::string &pruned) { - static const size_t pruned_len = 6; - static const size_t total_len = 70 + pruned_len; - - ssize_t drop_len = std::max(pruned.length() + 1, pruned_len); - ssize_t size_len = std::max(size.length() + 1, - total_len - name.length() - drop_len - 1); - - if (pruned.length()) { - return android::base::StringPrintf("%s%*s%*s\n", name.c_str(), - (int)size_len, size.c_str(), - (int)drop_len, pruned.c_str()); - } else { - return android::base::StringPrintf("%s%*s\n", name.c_str(), - (int)size_len, size.c_str()); - } +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(), android_log_id_to_name(id)), + std::string("Size"), + std::string(isprune ? "Pruned" : "")) + + formatLine(std::string("UID PACKAGE"), + std::string("BYTES"), + std::string(isprune ? "NUM" : "")); } -std::string LogStatistics::format(uid_t uid, unsigned int logMask) { +std::string UidEntry::format(const LogStatistics &stat, log_id_t /* id */) const { + uid_t uid = getKey(); + std::string name = android::base::StringPrintf("%u", uid); + const char *nameTmp = stat.uidToName(uid); + if (nameTmp) { + name += android::base::StringPrintf( + "%*s%s", (int)std::max(6 - name.length(), (size_t)1), + "", nameTmp); + free(const_cast(nameTmp)); + } + + std::string size = android::base::StringPrintf("%zu", getSizes()); + + std::string pruned = ""; + size_t dropped = getDropped(); + if (dropped) { + pruned = android::base::StringPrintf("%zu", dropped); + } + + return formatLine(name, size, pruned); +} + +std::string PidEntry::formatHeader(const std::string &name, log_id_t /* id */) const { + return formatLine(name, + std::string("Size"), + std::string("Pruned")) + + formatLine(std::string(" PID/UID COMMAND LINE"), + std::string("BYTES"), + std::string("NUM")); +} + +std::string PidEntry::format(const LogStatistics &stat, log_id_t /* id */) const { + uid_t uid = getUid(); + std::string name = android::base::StringPrintf("%5u/%u", + getKey(), uid); + const char *nameTmp = getName(); + if (nameTmp) { + name += android::base::StringPrintf( + "%*s%s", (int)std::max(12 - name.length(), (size_t)1), + "", nameTmp); + } else if ((nameTmp = stat.uidToName(uid))) { + name += android::base::StringPrintf( + "%*s%s", (int)std::max(12 - name.length(), (size_t)1), + "", nameTmp); + free(const_cast(nameTmp)); + } + + std::string size = android::base::StringPrintf("%zu", + getSizes()); + + std::string pruned = ""; + size_t dropped = getDropped(); + if (dropped) { + pruned = android::base::StringPrintf("%zu", dropped); + } + + return formatLine(name, size, pruned); +} + +std::string TidEntry::formatHeader(const std::string &name, log_id_t /* id */) const { + return formatLine(name, + std::string("Size"), + std::string("Pruned")) + + formatLine(std::string(" TID/UID COMM"), + std::string("BYTES"), + std::string("NUM")); +} + +std::string TidEntry::format(const LogStatistics &stat, log_id_t /* id */) const { + uid_t uid = getUid(); + std::string name = android::base::StringPrintf("%5u/%u", + getKey(), uid); + const char *nameTmp = getName(); + if (nameTmp) { + name += android::base::StringPrintf( + "%*s%s", (int)std::max(12 - name.length(), (size_t)1), + "", nameTmp); + } else if ((nameTmp = stat.uidToName(uid))) { + // if we do not have a PID name, lets punt to try UID name? + name += android::base::StringPrintf( + "%*s%s", (int)std::max(12 - name.length(), (size_t)1), + "", nameTmp); + free(const_cast(nameTmp)); + // We tried, better to not have a name at all, we still + // have TID/UID by number to report in any case. + } + + std::string size = android::base::StringPrintf("%zu", + getSizes()); + + std::string pruned = ""; + size_t dropped = getDropped(); + if (dropped) { + pruned = android::base::StringPrintf("%zu", dropped); + } + + return formatLine(name, size, pruned); +} + +std::string TagEntry::formatHeader(const std::string &name, log_id_t id) const { + bool isprune = worstUidEnabledForLogid(id); + return formatLine(name, + std::string("Size"), + std::string(isprune ? "Prune" : "")) + + formatLine(std::string(" TAG/UID TAGNAME"), + std::string("BYTES"), + std::string(isprune ? "NUM" : "")); +} + +std::string TagEntry::format(const LogStatistics & /* stat */, log_id_t /* id */) const { + std::string name; + uid_t uid = getUid(); + if (uid == (uid_t)-1) { + name = android::base::StringPrintf("%7u", + getKey()); + } else { + name = android::base::StringPrintf("%7u/%u", + getKey(), uid); + } + const char *nameTmp = getName(); + if (nameTmp) { + name += android::base::StringPrintf( + "%*s%s", (int)std::max(14 - name.length(), (size_t)1), + "", nameTmp); + } + + std::string size = android::base::StringPrintf("%zu", + getSizes()); + + std::string pruned = ""; + + return formatLine(name, size, pruned); +} + +std::string LogStatistics::format(uid_t uid, unsigned int logMask) const { static const unsigned short spaces_total = 19; // Report on total logging, current and for all time @@ -227,7 +348,7 @@ std::string LogStatistics::format(uid_t uid, unsigned int logMask) { } spaces = 4; - output += android::base::StringPrintf("\nTotal"); + output += "\nTotal"; log_id_for_each(id) { if (!(logMask & (1 << id))) { @@ -244,7 +365,7 @@ std::string LogStatistics::format(uid_t uid, unsigned int logMask) { } spaces = 6; - output += android::base::StringPrintf("\nNow"); + output += "\nNow"; log_id_for_each(id) { if (!(logMask & (1 << id))) { @@ -266,245 +387,30 @@ std::string LogStatistics::format(uid_t uid, unsigned int logMask) { // Report on Chattiest + std::string name; + // Chattiest by application (UID) - static const size_t maximum_sorted_entries = 32; log_id_for_each(id) { if (!(logMask & (1 << id))) { continue; } - bool headerPrinted = false; - std::unique_ptr sorted = sort(maximum_sorted_entries, id); - ssize_t index = -1; - while ((index = uidTable_t::next(index, sorted, maximum_sorted_entries)) >= 0) { - const UidEntry *entry = sorted[index]; - uid_t u = entry->getKey(); - if ((uid != AID_ROOT) && (u != uid)) { - continue; - } - - if (!headerPrinted) { - output += android::base::StringPrintf("\n\n"); - std::string name; - if (uid == AID_ROOT) { - name = android::base::StringPrintf( - "Chattiest UIDs in %s log buffer:", - android_log_id_to_name(id)); - } else { - name = android::base::StringPrintf( - "Logging for your UID in %s log buffer:", - android_log_id_to_name(id)); - } - std::string size = "Size"; - std::string pruned = "Pruned"; - if (!worstUidEnabledForLogid(id)) { - pruned = ""; - } - output += format_line(name, size, pruned); - - name = "UID PACKAGE"; - size = "BYTES"; - pruned = "LINES"; - if (!worstUidEnabledForLogid(id)) { - pruned = ""; - } - output += format_line(name, size, pruned); - - headerPrinted = true; - } - - std::string name = android::base::StringPrintf("%u", u); - char *n = uidToName(u); - if (n) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(6 - name.length(), (size_t)1), - "", n); - free(n); - } - - std::string size = android::base::StringPrintf("%zu", - entry->getSizes()); - - std::string pruned = ""; - size_t dropped = entry->getDropped(); - if (dropped) { - pruned = android::base::StringPrintf("%zu", dropped); - } - - output += format_line(name, size, pruned); - } + name = (uid == AID_ROOT) + ? "Chattiest UIDs in %s log buffer:" + : "Logging for your UID in %s log buffer:"; + output += uidTable[id].format(*this, uid, name, id); } if (enable) { - // Pid table - bool headerPrinted = false; - std::unique_ptr sorted = pidTable.sort(maximum_sorted_entries); - ssize_t index = -1; - while ((index = pidTable.next(index, sorted, maximum_sorted_entries)) >= 0) { - const PidEntry *entry = sorted[index]; - uid_t u = entry->getUid(); - if ((uid != AID_ROOT) && (u != uid)) { - continue; - } - - if (!headerPrinted) { - output += android::base::StringPrintf("\n\n"); - std::string name; - if (uid == AID_ROOT) { - name = android::base::StringPrintf("Chattiest PIDs:"); - } else { - name = android::base::StringPrintf("Logging for this PID:"); - } - std::string size = "Size"; - std::string pruned = "Pruned"; - output += format_line(name, size, pruned); - - name = " PID/UID COMMAND LINE"; - size = "BYTES"; - pruned = "LINES"; - output += format_line(name, size, pruned); - - headerPrinted = true; - } - - std::string name = android::base::StringPrintf("%5u/%u", - entry->getKey(), u); - const char *n = entry->getName(); - if (n) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(12 - name.length(), (size_t)1), - "", n); - } else { - char *un = uidToName(u); - if (un) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(12 - name.length(), (size_t)1), - "", un); - free(un); - } - } - - std::string size = android::base::StringPrintf("%zu", - entry->getSizes()); - - std::string pruned = ""; - size_t dropped = entry->getDropped(); - if (dropped) { - pruned = android::base::StringPrintf("%zu", dropped); - } - - output += format_line(name, size, pruned); - } - } - - if (enable) { - // Tid table - bool headerPrinted = false; - // sort() returns list of references, unique_ptr makes sure self-delete - std::unique_ptr sorted = tidTable.sort(maximum_sorted_entries); - ssize_t index = -1; - while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) { - const TidEntry *entry = sorted[index]; - uid_t u = entry->getUid(); - if ((uid != AID_ROOT) && (u != uid)) { - continue; - } - - if (!headerPrinted) { // Only print header if we have table to print - output += android::base::StringPrintf("\n\n"); - std::string name = "Chattiest TIDs:"; - std::string size = "Size"; - std::string pruned = "Pruned"; - output += format_line(name, size, pruned); - - name = " TID/UID COMM"; - size = "BYTES"; - pruned = "LINES"; - output += format_line(name, size, pruned); - - headerPrinted = true; - } - - std::string name = android::base::StringPrintf("%5u/%u", - entry->getKey(), u); - const char *n = entry->getName(); - if (n) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(12 - name.length(), (size_t)1), - "", n); - } else { - // if we do not have a PID name, lets punt to try UID name? - char *un = uidToName(u); - if (un) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(12 - name.length(), (size_t)1), - "", un); - free(un); - } - // We tried, better to not have a name at all, we still - // have TID/UID by number to report in any case. - } - - std::string size = android::base::StringPrintf("%zu", - entry->getSizes()); - - std::string pruned = ""; - size_t dropped = entry->getDropped(); - if (dropped) { - pruned = android::base::StringPrintf("%zu", dropped); - } - - output += format_line(name, size, pruned); - } + name = (uid == AID_ROOT) ? "Chattiest PIDs:" : "Logging for this PID:"; + output += pidTable.format(*this, uid, name); + name = "Chattiest TIDs:"; + output += tidTable.format(*this, uid, name); } if (enable && (logMask & (1 << LOG_ID_EVENTS))) { - // Tag table - bool headerPrinted = false; - std::unique_ptr sorted = tagTable.sort(maximum_sorted_entries); - ssize_t index = -1; - while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) { - const TagEntry *entry = sorted[index]; - uid_t u = entry->getUid(); - if ((uid != AID_ROOT) && (u != uid)) { - continue; - } - - std::string pruned = ""; - - if (!headerPrinted) { - output += android::base::StringPrintf("\n\n"); - std::string name = "Chattiest events log buffer TAGs:"; - std::string size = "Size"; - output += format_line(name, size, pruned); - - name = " TAG/UID TAGNAME"; - size = "BYTES"; - output += format_line(name, size, pruned); - - headerPrinted = true; - } - - std::string name; - if (u == (uid_t)-1) { - name = android::base::StringPrintf("%7u", - entry->getKey()); - } else { - name = android::base::StringPrintf("%7u/%u", - entry->getKey(), u); - } - const char *n = entry->getName(); - if (n) { - name += android::base::StringPrintf( - "%*s%s", (int)std::max(14 - name.length(), (size_t)1), - "", n); - } - - std::string size = android::base::StringPrintf("%zu", - entry->getSizes()); - - output += format_line(name, size, pruned); - } + name = "Chattiest events log buffer TAGs:"; + output += tagTable.format(*this, uid, name, LOG_ID_EVENTS); } return output; @@ -536,8 +442,10 @@ uid_t LogStatistics::pidToUid(pid_t pid) { } // caller must free character string -char *LogStatistics::pidToName(pid_t pid) { - const char *name = pidTable.add(pid)->second.getName(); +const char *LogStatistics::pidToName(pid_t pid) const { + // An inconvenient truth ... getName() can alter the object + pidTable_t &writablePidTable = const_cast(pidTable); + const char *name = writablePidTable.add(pid)->second.getName(); if (!name) { return NULL; } diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index 5a44d59ab..dd133803d 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -21,9 +21,13 @@ #include #include +#include // std::max +#include // std::string #include +#include #include +#include #include "LogBufferElement.h" #include "LogUtils.h" @@ -31,6 +35,8 @@ #define log_id_for_each(i) \ for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1)) +class LogStatistics; + template class LogHashtable { @@ -39,50 +45,43 @@ class LogHashtable { public: typedef typename std::unordered_map::iterator iterator; + typedef typename std::unordered_map::const_iterator const_iterator; - std::unique_ptr sort(size_t n) { - if (!n) { + std::unique_ptr sort(size_t len) const { + if (!len) { std::unique_ptr sorted(NULL); return sorted; } - const TEntry **retval = new const TEntry* [n]; - memset(retval, 0, sizeof(*retval) * n); + const TEntry **retval = new const TEntry* [len]; + memset(retval, 0, sizeof(*retval) * len); - for(iterator it = map.begin(); it != map.end(); ++it) { + for(const_iterator it = map.begin(); it != map.end(); ++it) { const TEntry &entry = it->second; - size_t s = entry.getSizes(); - ssize_t i = n - 1; - while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0)) + size_t sizes = entry.getSizes(); + ssize_t index = len - 1; + while ((!retval[index] || (sizes > retval[index]->getSizes())) + && (--index >= 0)) ; - if (++i < (ssize_t)n) { - size_t b = n - i - 1; - if (b) { - memmove(&retval[i+1], &retval[i], b * sizeof(retval[0])); + if (++index < (ssize_t)len) { + size_t num = len - index - 1; + if (num) { + memmove(&retval[index + 1], &retval[index], + num * sizeof(retval[0])); } - retval[i] = &entry; + retval[index] = &entry; } } std::unique_ptr sorted(retval); return sorted; } - // Iteration handler for the sort method output - static ssize_t next(ssize_t index, std::unique_ptr &sorted, size_t n) { - ++index; - if (!sorted.get() || (index < 0) || (n <= (size_t)index) || !sorted[index] - || (sorted[index]->getSizes() <= (sorted[0]->getSizes() / 100))) { - return -1; - } - return index; - } - - inline iterator add(TKey key, LogBufferElement *e) { + inline iterator add(TKey key, LogBufferElement *element) { iterator it = map.find(key); if (it == map.end()) { - it = map.insert(std::make_pair(key, TEntry(e))).first; + it = map.insert(std::make_pair(key, TEntry(element))).first; } else { - it->second.add(e); + it->second.add(element); } return it; } @@ -97,65 +96,138 @@ public: return it; } - void subtract(TKey key, LogBufferElement *e) { + void subtract(TKey key, LogBufferElement *element) { iterator it = map.find(key); - if ((it != map.end()) && it->second.subtract(e)) { + if ((it != map.end()) && it->second.subtract(element)) { map.erase(it); } } - inline void drop(TKey key, LogBufferElement *e) { + inline void drop(TKey key, LogBufferElement *element) { iterator it = map.find(key); if (it != map.end()) { - it->second.drop(e); + it->second.drop(element); } } inline iterator begin() { return map.begin(); } + inline const_iterator begin() const { return map.begin(); } inline iterator end() { return map.end(); } + inline const_iterator end() const { return map.end(); } + std::string format( + const LogStatistics &stat, + uid_t uid, + 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 sorted = sort(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 ((uid != AID_ROOT) && (uid != entry->getUid())) { + continue; + } + if (!headerPrinted) { + output += "\n\n"; + output += entry->formatHeader(name, id); + headerPrinted = true; + } + output += entry->format(stat, id); + } + return output; + } }; +namespace EntryBaseConstants { + static constexpr size_t pruned_len = 14; + static constexpr size_t total_len = 80; +} + struct EntryBase { size_t size; EntryBase():size(0) { } - EntryBase(LogBufferElement *e):size(e->getMsgLen()) { } + EntryBase(LogBufferElement *element):size(element->getMsgLen()) { } size_t getSizes() const { return size; } - inline void add(LogBufferElement *e) { size += e->getMsgLen(); } - inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; } + inline void add(LogBufferElement *element) { size += element->getMsgLen(); } + inline bool subtract(LogBufferElement *element) { + size -= element->getMsgLen(); + return !size; + } + + static std::string formatLine( + const std::string &name, + const std::string &size, + const std::string &pruned) { + ssize_t drop_len = std::max(pruned.length() + 1, + EntryBaseConstants::pruned_len); + ssize_t size_len = std::max(size.length() + 1, + EntryBaseConstants::total_len + - name.length() - drop_len - 1); + + if (pruned.length()) { + return android::base::StringPrintf("%s%*s%*s\n", name.c_str(), + (int)size_len, size.c_str(), + (int)drop_len, pruned.c_str()); + } else { + return android::base::StringPrintf("%s%*s\n", name.c_str(), + (int)size_len, size.c_str()); + } + } }; struct EntryBaseDropped : public EntryBase { size_t dropped; EntryBaseDropped():dropped(0) { } - EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ } + EntryBaseDropped(LogBufferElement *element): + EntryBase(element), + dropped(element->getDropped()){ + } size_t getDropped() const { return dropped; } - inline void add(LogBufferElement *e) { - dropped += e->getDropped(); - EntryBase::add(e); + inline void add(LogBufferElement *element) { + dropped += element->getDropped(); + EntryBase::add(element); } - inline bool subtract(LogBufferElement *e) { - dropped -= e->getDropped(); - return EntryBase::subtract(e) && !dropped; + inline bool subtract(LogBufferElement *element) { + dropped -= element->getDropped(); + return EntryBase::subtract(element) && !dropped; } - inline void drop(LogBufferElement *e) { + inline void drop(LogBufferElement *element) { dropped += 1; - EntryBase::subtract(e); + EntryBase::subtract(element); } }; struct UidEntry : public EntryBaseDropped { const uid_t uid; - UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { } + UidEntry(LogBufferElement *element): + EntryBaseDropped(element), + uid(element->getUid()) { + } inline const uid_t&getKey() const { return uid; } + inline const uid_t&getUid() const { return uid; } + + std::string formatHeader(const std::string &name, log_id_t id) const; + std::string format(const LogStatistics &stat, log_id_t id) const; }; namespace android { @@ -167,51 +239,54 @@ struct PidEntry : public EntryBaseDropped { uid_t uid; char *name; - PidEntry(pid_t p): - EntryBaseDropped(), - pid(p), - uid(android::pidToUid(p)), - name(android::pidToName(pid)) { } - PidEntry(LogBufferElement *e): - EntryBaseDropped(e), - pid(e->getPid()), - uid(e->getUid()), - name(android::pidToName(e->getPid())) { } - PidEntry(const PidEntry &c): - EntryBaseDropped(c), - pid(c.pid), - uid(c.uid), - name(c.name ? strdup(c.name) : NULL) { } + PidEntry(pid_t pid): + EntryBaseDropped(), + pid(pid), + uid(android::pidToUid(pid)), + name(android::pidToName(pid)) { + } + PidEntry(LogBufferElement *element): + EntryBaseDropped(element), + pid(element->getPid()), + uid(element->getUid()), + name(android::pidToName(pid)) { + } + PidEntry(const PidEntry &element): + EntryBaseDropped(element), + pid(element.pid), + uid(element.uid), + name(element.name ? strdup(element.name) : NULL) { + } ~PidEntry() { free(name); } const pid_t&getKey() const { return pid; } const uid_t&getUid() const { return uid; } const char*getName() const { return name; } - inline void add(pid_t p) { + inline void add(pid_t newPid) { if (name && !fast(name, "zygote", 6)) { free(name); name = NULL; } if (!name) { - char *n = android::pidToName(p); - if (n) { - name = n; - } + name = android::pidToName(newPid); } } - inline void add(LogBufferElement *e) { - uid_t u = e->getUid(); - if (getUid() != u) { - uid = u; + inline void add(LogBufferElement *element) { + uid_t incomingUid = element->getUid(); + if (getUid() != incomingUid) { + uid = incomingUid; free(name); - name = android::pidToName(e->getPid()); + name = android::pidToName(element->getPid()); } else { - add(e->getPid()); + add(element->getPid()); } - EntryBaseDropped::add(e); + EntryBaseDropped::add(element); } + + std::string formatHeader(const std::string &name, log_id_t id) const; + std::string format(const LogStatistics &stat, log_id_t id) const; }; struct TidEntry : public EntryBaseDropped { @@ -219,73 +294,80 @@ struct TidEntry : public EntryBaseDropped { uid_t uid; char *name; - TidEntry(pid_t t): - EntryBaseDropped(), - tid(t), - uid(android::pidToUid(t)), - name(android::tidToName(tid)) { } - TidEntry(LogBufferElement *e): - EntryBaseDropped(e), - tid(e->getTid()), - uid(e->getUid()), - name(android::tidToName(e->getTid())) { } - TidEntry(const TidEntry &c): - EntryBaseDropped(c), - tid(c.tid), - uid(c.uid), - name(c.name ? strdup(c.name) : NULL) { } + TidEntry(pid_t tid): + EntryBaseDropped(), + tid(tid), + uid(android::pidToUid(tid)), + name(android::tidToName(tid)) { + } + TidEntry(LogBufferElement *element): + EntryBaseDropped(element), + tid(element->getTid()), + uid(element->getUid()), + name(android::tidToName(tid)) { + } + TidEntry(const TidEntry &element): + EntryBaseDropped(element), + tid(element.tid), + uid(element.uid), + name(element.name ? strdup(element.name) : NULL) { + } ~TidEntry() { free(name); } const pid_t&getKey() const { return tid; } const uid_t&getUid() const { return uid; } const char*getName() const { return name; } - inline void add(pid_t t) { + inline void add(pid_t incomingTid) { if (name && !fast(name, "zygote", 6)) { free(name); name = NULL; } if (!name) { - char *n = android::tidToName(t); - if (n) { - name = n; - } + name = android::tidToName(incomingTid); } } - inline void add(LogBufferElement *e) { - uid_t u = e->getUid(); - if (getUid() != u) { - uid = u; + inline void add(LogBufferElement *element) { + uid_t incomingUid = element->getUid(); + if (getUid() != incomingUid) { + uid = incomingUid; free(name); - name = android::tidToName(e->getTid()); + name = android::tidToName(element->getTid()); } else { - add(e->getTid()); + add(element->getTid()); } - EntryBaseDropped::add(e); + EntryBaseDropped::add(element); } + + std::string formatHeader(const std::string &name, log_id_t id) const; + std::string format(const LogStatistics &stat, log_id_t id) const; }; struct TagEntry : public EntryBase { const uint32_t tag; uid_t uid; - TagEntry(LogBufferElement *e): - EntryBase(e), - tag(e->getTag()), - uid(e->getUid()) { } + TagEntry(LogBufferElement *element): + EntryBase(element), + tag(element->getTag()), + uid(element->getUid()) { + } const uint32_t&getKey() const { return tag; } const uid_t&getUid() const { return uid; } const char*getName() const { return android::tagToName(tag); } - inline void add(LogBufferElement *e) { - uid_t u = e->getUid(); - if (uid != u) { + inline void add(LogBufferElement *element) { + uid_t incomingUid = element->getUid(); + if (uid != incomingUid) { uid = -1; } - EntryBase::add(e); + EntryBase::add(element); } + + std::string formatHeader(const std::string &name, log_id_t id) const; + std::string format(const LogStatistics &stat, log_id_t id) const; }; // Log Statistics @@ -324,7 +406,9 @@ public: // Correct for merging two entries referencing dropped content void erase(LogBufferElement *e) { --mElements[e->getLogId()]; } - std::unique_ptr sort(size_t n, log_id i) { return uidTable[i].sort(n); } + std::unique_ptr sort(size_t len, log_id id) { + return uidTable[id].sort(len); + } // fast track current value by id only size_t sizes(log_id_t id) const { return mSizes[id]; } @@ -332,12 +416,12 @@ public: size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; } size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; } - std::string format(uid_t uid, unsigned int logMask); + std::string format(uid_t uid, unsigned int logMask) const; // helper (must be locked directly or implicitly by mLogElementsLock) - char *pidToName(pid_t pid); + const char *pidToName(pid_t pid) const; uid_t pidToUid(pid_t pid); - char *uidToName(uid_t uid); + const char *uidToName(uid_t uid) const; }; #endif // _LOGD_LOG_STATISTICS_H__