summaryrefslogtreecommitdiffstats
path: root/logd
diff options
context:
space:
mode:
authorMark Salyzyn <salyzyn@google.com>2015-03-10 13:51:35 -0700
committerMark Salyzyn <salyzyn@google.com>2015-03-20 12:31:23 -0700
commit97c1c2beee2cbd8c67c1cd507367e5b084d853c8 (patch)
tree11842d8e150816d839e355582671dad82278ade5 /logd
parentca87790cdccdb0ee17fb4069e6d4ed1e7b4e2ee0 (diff)
downloadsystem_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.zip
system_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.tar.gz
system_core-97c1c2beee2cbd8c67c1cd507367e5b084d853c8.tar.bz2
logd: optimize statistics
- Go back to basic requirements - Simplify - use hash tables to minimize memory impact Bug: 19608965 Change-Id: If7becb34354d6415e5c387ecea7d4109a15259c8
Diffstat (limited to 'logd')
-rw-r--r--logd/LogBuffer.cpp169
-rw-r--r--logd/LogBuffer.h2
-rw-r--r--logd/LogBufferElement.h3
-rw-r--r--logd/LogStatistics.cpp864
-rw-r--r--logd/LogStatistics.h165
-rw-r--r--logd/LogWhiteBlackList.h2
6 files changed, 281 insertions, 924 deletions
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 2693583..d11b129 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -27,8 +27,6 @@
#include "LogBuffer.h"
#include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogWhiteBlackList.h"
// Default
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
@@ -193,7 +191,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
LogTimeEntry::unlock();
}
- stats.add(len, log_id, uid, pid);
+ stats.add(elem);
maybePrune(log_id);
pthread_mutex_unlock(&mLogElementsLock);
}
@@ -216,6 +214,16 @@ void LogBuffer::maybePrune(log_id_t id) {
}
}
+LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
+ LogBufferElement *e = *it;
+
+ it = mLogElements.erase(it);
+ stats.subtract(e);
+ delete e;
+
+ return it;
+}
+
// prune "pruneRows" of type "id" from the buffer.
//
// mLogElementsLock must be held when this function is called.
@@ -250,12 +258,8 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
continue;
}
- uid_t uid = e->getUid();
-
- if (uid == caller_uid) {
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, uid, e->getPid());
- delete e;
+ if (e->getUid() == caller_uid) {
+ it = erase(it);
pruneRows--;
if (pruneRows == 0) {
break;
@@ -269,6 +273,7 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
}
// prune by worst offender by uid
+ bool hasBlacklist = mPrune.naughty();
while (pruneRows > 0) {
// recalculate the worst offender on every batched pass
uid_t worst = (uid_t) -1;
@@ -276,19 +281,23 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
size_t second_worst_sizes = 0;
if ((id != LOG_ID_CRASH) && mPrune.worstUidEnabled()) {
- LidStatistics &l = stats.id(id);
- l.sort();
- UidStatisticsCollection::iterator iu = l.begin();
- if (iu != l.end()) {
- UidStatistics *u = *iu;
- worst = u->getUid();
- worst_sizes = u->sizes();
- if (++iu != l.end()) {
- second_worst_sizes = (*iu)->sizes();
+ const UidEntry **sorted = stats.sort(2, id);
+
+ if (sorted) {
+ if (sorted[0] && sorted[1]) {
+ worst = sorted[0]->getKey();
+ worst_sizes = sorted[0]->getSizes();
+ second_worst_sizes = sorted[1]->getSizes();
}
+ delete [] sorted;
}
}
+ // skip if we have neither worst nor naughty filters
+ if ((worst == (uid_t) -1) && !hasBlacklist) {
+ break;
+ }
+
bool kick = false;
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
@@ -304,24 +313,28 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
uid_t uid = e->getUid();
- if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
- it = mLogElements.erase(it);
- unsigned short len = e->getMsgLen();
- stats.subtract(len, id, uid, e->getPid());
- delete e;
- pruneRows--;
- if (uid == worst) {
- kick = true;
- if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
- break;
- }
- worst_sizes -= len;
- } else if (pruneRows == 0) {
- break;
- }
- } else {
+ // !Worst and !BlackListed?
+ if ((uid != worst) && (!hasBlacklist || !mPrune.naughty(e))) {
++it;
+ continue;
+ }
+
+ unsigned short len = e->getMsgLen();
+ it = erase(it);
+ pruneRows--;
+ if (pruneRows == 0) {
+ break;
+ }
+
+ if (uid != worst) {
+ continue;
+ }
+
+ kick = true;
+ if (worst_sizes < second_worst_sizes) {
+ break;
}
+ worst_sizes -= len;
}
if (!kick || !mPrune.worstUidEnabled()) {
@@ -330,58 +343,63 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
}
bool whitelist = false;
+ bool hasWhitelist = mPrune.nice();
it = mLogElements.begin();
while((pruneRows > 0) && (it != mLogElements.end())) {
LogBufferElement *e = *it;
- if (e->getLogId() == id) {
- 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
- oldest->release_Locked();
- } else {
- oldest->triggerSkip_Locked(id, pruneRows);
- }
- }
+
+ if (e->getLogId() != id) {
+ it++;
+ continue;
+ }
+
+ if (oldest && (oldest->mStart <= e->getSequence())) {
+ if (whitelist) {
break;
}
- if (mPrune.nice(e)) { // WhiteListed
- whitelist = true;
- it++;
- continue;
+ if (stats.sizes(id) > (2 * log_buffer_size(id))) {
+ // kick a misbehaving log reader client off the island
+ oldest->release_Locked();
+ } else {
+ oldest->triggerSkip_Locked(id, pruneRows);
}
+ break;
+ }
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
+ if (hasWhitelist && mPrune.nice(e)) { // WhiteListed
+ whitelist = true;
it++;
+ continue;
}
+
+ it = erase(it);
+ pruneRows--;
}
+ // Do not save the whitelist if we are reader range limited
if (whitelist && (pruneRows > 0)) {
it = mLogElements.begin();
while((it != mLogElements.end()) && (pruneRows > 0)) {
LogBufferElement *e = *it;
- if (e->getLogId() == id) {
- 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();
- } else {
- oldest->triggerSkip_Locked(id, pruneRows);
- }
- break;
+
+ if (e->getLogId() != id) {
+ ++it;
+ continue;
+ }
+
+ 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();
+ } else {
+ oldest->triggerSkip_Locked(id, pruneRows);
}
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
- delete e;
- pruneRows--;
- } else {
- it++;
+ break;
}
+
+ it = erase(it);
+ pruneRows--;
}
}
@@ -487,22 +505,9 @@ uint64_t LogBuffer::flushTo(
}
void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
- uint64_t oldest = UINT64_MAX;
-
pthread_mutex_lock(&mLogElementsLock);
- // Find oldest element in the log(s)
- LogBufferElementCollection::iterator it;
- for (it = mLogElements.begin(); it != mLogElements.end(); ++it) {
- LogBufferElement *element = *it;
-
- if ((logMask & (1 << element->getLogId()))) {
- oldest = element->getSequence();
- break;
- }
- }
-
- stats.format(strp, uid, logMask, oldest);
+ stats.format(strp, uid, logMask);
pthread_mutex_unlock(&mLogElementsLock);
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 13e6aa8..a29e015 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -78,7 +78,7 @@ public:
private:
void maybePrune(log_id_t id);
void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
-
+ LogBufferElementCollection::iterator erase(LogBufferElementCollection::iterator it);
};
#endif // _LOGD_LOG_BUFFER_H__
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 25f1450..0628d3e 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -17,8 +17,9 @@
#ifndef _LOGD_LOG_BUFFER_ELEMENT_H__
#define _LOGD_LOG_BUFFER_ELEMENT_H__
-#include <sys/types.h>
#include <stdatomic.h>
+#include <sys/types.h>
+
#include <sysutils/SocketClient.h>
#include <log/log.h>
#include <log/log_read.h>
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 5a70689..19d599c 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+#include <algorithm> // std::max
#include <fcntl.h>
-#include <malloc.h>
-#include <stdarg.h>
-#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <log/logger.h>
#include <private/android_filesystem_config.h>
@@ -25,80 +27,21 @@
#include "LogStatistics.h"
-PidStatistics::PidStatistics(pid_t pid, char *name)
- : pid(pid)
- , mSizesTotal(0)
- , mElementsTotal(0)
- , mSizes(0)
- , mElements(0)
- , name(name)
- , mGone(false)
-{ }
-
-#ifdef DO_NOT_ERROR_IF_PIDSTATISTICS_USES_A_COPY_CONSTRUCTOR
-PidStatistics::PidStatistics(const PidStatistics &copy)
- : pid(copy->pid)
- , name(copy->name ? strdup(copy->name) : NULL)
- , mSizesTotal(copy->mSizesTotal)
- , mElementsTotal(copy->mElementsTotal)
- , mSizes(copy->mSizes)
- , mElements(copy->mElements)
- , mGone(copy->mGone)
-{ }
-#endif
-
-PidStatistics::~PidStatistics() {
- free(name);
-}
-
-bool PidStatistics::pidGone() {
- if (mGone || (pid == gone)) {
- return true;
- }
- if (pid == 0) {
- return false;
- }
- if (kill(pid, 0) && (errno != EPERM)) {
- mGone = true;
- return true;
- }
- return false;
-}
-
-void PidStatistics::setName(char *new_name) {
- free(name);
- name = new_name;
-}
-
-void PidStatistics::add(unsigned short size) {
- mSizesTotal += size;
- ++mElementsTotal;
- mSizes += size;
- ++mElements;
-}
-
-bool PidStatistics::subtract(unsigned short size) {
- mSizes -= size;
- --mElements;
- return (mElements == 0) && pidGone();
-}
-
-void PidStatistics::addTotal(size_t size, size_t element) {
- if (pid == gone) {
- mSizesTotal += size;
- mElementsTotal += element;
+LogStatistics::LogStatistics() {
+ log_id_for_each(id) {
+ mSizes[id] = 0;
+ mElements[id] = 0;
+ mSizesTotal[id] = 0;
+ mElementsTotal[id] = 0;
}
}
-// must call free to release return value
-// If only we could sniff our own logs for:
-// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
-// which debuggerd prints as a process is crashing.
-char *PidStatistics::pidToName(pid_t pid) {
+// caller must own and free character string
+char *LogStatistics::pidToName(pid_t pid) {
char *retval = NULL;
if (pid == 0) { // special case from auditd for kernel
retval = strdup("logd.auditd");
- } else if (pid != gone) {
+ } else {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
@@ -117,358 +60,105 @@ char *PidStatistics::pidToName(pid_t pid) {
return retval;
}
-UidStatistics::UidStatistics(uid_t uid)
- : uid(uid)
- , mSizes(0)
- , mElements(0) {
- Pids.clear();
-}
-
-UidStatistics::~UidStatistics() {
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end();) {
- delete (*it);
- it = erase(it);
- }
-}
+void LogStatistics::add(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
+ mSizes[log_id] += size;
+ ++mElements[log_id];
-void UidStatistics::add(unsigned short size, pid_t pid) {
- mSizes += size;
- ++mElements;
-
- PidStatistics *p = NULL;
- PidStatisticsCollection::iterator last;
- PidStatisticsCollection::iterator it;
- for (last = it = begin(); it != end(); last = it, ++it) {
- p = *it;
- if (pid == p->getPid()) {
- p->add(size);
- return;
- }
- }
- // insert if the gone entry.
- bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
- p = new PidStatistics(pid, pidToName(pid));
- if (insert_before_last) {
- insert(last, p);
+ uid_t uid = e->getUid();
+ android::hash_t hash = android::hash_type(uid);
+ uidTable_t &table = uidTable[log_id];
+ ssize_t index = table.find(-1, hash, uid);
+ if (index == -1) {
+ UidEntry initEntry(uid);
+ initEntry.add(size);
+ table.add(hash, initEntry);
} else {
- push_back(p);
+ UidEntry &entry = table.editEntryAt(index);
+ entry.add(size);
}
- p->add(size);
-}
-
-void UidStatistics::subtract(unsigned short size, pid_t pid) {
- mSizes -= size;
- --mElements;
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- if (p->subtract(size)) {
- size_t szsTotal = p->sizesTotal();
- size_t elsTotal = p->elementsTotal();
- delete p;
- erase(it);
- it = end();
- --it;
- if (it == end()) {
- p = new PidStatistics(p->gone);
- push_back(p);
- } else {
- p = *it;
- if (p->getPid() != p->gone) {
- p = new PidStatistics(p->gone);
- push_back(p);
- }
- }
- p->addTotal(szsTotal, elsTotal);
- }
- return;
- }
- }
-}
-
-void UidStatistics::sort() {
- for (bool pass = true; pass;) {
- pass = false;
- PidStatisticsCollection::iterator it = begin();
- if (it != end()) {
- PidStatisticsCollection::iterator lt = it;
- PidStatistics *l = (*lt);
- while (++it != end()) {
- PidStatistics *n = (*it);
- if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
- pass = true;
- erase(it);
- insert(lt, n);
- it = lt;
- n = l;
- }
- lt = it;
- l = n;
- }
- }
- }
-}
-size_t UidStatistics::sizes(pid_t pid) {
- if (pid == pid_all) {
- return sizes();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->sizes();
- }
- }
- return 0;
+ mSizesTotal[log_id] += size;
+ ++mElementsTotal[log_id];
}
-size_t UidStatistics::elements(pid_t pid) {
- if (pid == pid_all) {
- return elements();
- }
-
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if (pid == p->getPid()) {
- return p->elements();
- }
- }
- return 0;
-}
-
-size_t UidStatistics::sizesTotal(pid_t pid) {
- size_t sizes = 0;
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- sizes += p->sizesTotal();
- }
- }
- return sizes;
-}
+void LogStatistics::subtract(LogBufferElement *e) {
+ log_id_t log_id = e->getLogId();
+ unsigned short size = e->getMsgLen();
+ mSizes[log_id] -= size;
+ --mElements[log_id];
-size_t UidStatistics::elementsTotal(pid_t pid) {
- size_t elements = 0;
- PidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- PidStatistics *p = *it;
- if ((pid == pid_all) || (pid == p->getPid())) {
- elements += p->elementsTotal();
+ uid_t uid = e->getUid();
+ android::hash_t hash = android::hash_type(uid);
+ uidTable_t &table = uidTable[log_id];
+ ssize_t index = table.find(-1, hash, uid);
+ if (index != -1) {
+ UidEntry &entry = table.editEntryAt(index);
+ if (entry.subtract(size)) {
+ table.removeAt(index);
}
}
- return elements;
-}
-
-LidStatistics::LidStatistics() {
- Uids.clear();
}
-LidStatistics::~LidStatistics() {
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end();) {
- delete (*it);
- it = Uids.erase(it);
+// caller must own and delete UidEntry array
+const UidEntry **LogStatistics::sort(size_t n, log_id id) {
+ if (!n) {
+ return NULL;
}
-}
-
-void LidStatistics::add(unsigned short size, uid_t uid, pid_t pid) {
- UidStatistics *u;
- UidStatisticsCollection::iterator it;
- UidStatisticsCollection::iterator last;
- if (uid == (uid_t) -1) { // init
- uid = (uid_t) AID_ROOT;
- }
+ const UidEntry **retval = new const UidEntry* [n];
+ memset(retval, 0, sizeof(*retval) * n);
- for (last = it = begin(); it != end(); last = it, ++it) {
- u = *it;
- if (uid == u->getUid()) {
- u->add(size, pid);
- if ((last != it) && ((*last)->sizesTotal() < u->sizesTotal())) {
- Uids.erase(it);
- Uids.insert(last, u);
- }
- return;
- }
- }
- u = new UidStatistics(uid);
- if ((last != it) && ((*last)->sizesTotal() < (size_t) size)) {
- Uids.insert(last, u);
- } else {
- Uids.push_back(u);
- }
- u->add(size, pid);
-}
-
-void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
- if (uid == (uid_t) -1) { // init
- uid = (uid_t) AID_ROOT;
- }
-
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if (uid == u->getUid()) {
- u->subtract(size, pid);
- return;
- }
- }
-}
-
-void LidStatistics::sort() {
- for (bool pass = true; pass;) {
- pass = false;
- UidStatisticsCollection::iterator it = begin();
- if (it != end()) {
- UidStatisticsCollection::iterator lt = it;
- UidStatistics *l = (*lt);
- while (++it != end()) {
- UidStatistics *n = (*it);
- if (n->sizes() > l->sizes()) {
- pass = true;
- Uids.erase(it);
- Uids.insert(lt, n);
- it = lt;
- n = l;
- }
- lt = it;
- l = n;
+ uidTable_t &table = uidTable[id];
+ ssize_t index = -1;
+ while ((index = table.next(index)) >= 0) {
+ const UidEntry &entry = table.entryAt(index);
+ size_t s = entry.getSizes();
+ ssize_t i = n - 1;
+ while ((!retval[i] || (s > retval[i]->getSizes())) && (--i >= 0));
+ if (++i < (ssize_t)n) {
+ size_t b = n - i - 1;
+ if (b) {
+ memmove(&retval[i+1], &retval[i], b * sizeof(retval[0]));
}
+ retval[i] = &entry;
}
}
+ return retval;
}
-size_t LidStatistics::sizes(uid_t uid, pid_t pid) {
- size_t sizes = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- sizes += u->sizes(pid);
- }
+// caller must own and free character string
+char *LogStatistics::uidToName(uid_t uid) {
+ // Local hard coded favourites
+ if (uid == AID_LOGD) {
+ return strdup("auditd");
}
- return sizes;
-}
-size_t LidStatistics::elements(uid_t uid, pid_t pid) {
- size_t elements = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- elements += u->elements(pid);
- }
- }
- return elements;
-}
+ // Android hard coded
+ const struct android_id_info *info = android_ids;
-size_t LidStatistics::sizesTotal(uid_t uid, pid_t pid) {
- size_t sizes = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- sizes += u->sizesTotal(pid);
+ for (size_t i = 0; i < android_id_count; ++i) {
+ if (info->aid == uid) {
+ return strdup(info->name);
}
+ ++info;
}
- return sizes;
-}
-
-size_t LidStatistics::elementsTotal(uid_t uid, pid_t pid) {
- size_t elements = 0;
- UidStatisticsCollection::iterator it;
- for (it = begin(); it != end(); ++it) {
- UidStatistics *u = *it;
- if ((uid == uid_all) || (uid == u->getUid())) {
- elements += u->elementsTotal(pid);
- }
- }
- return elements;
-}
-
-LogStatistics::LogStatistics()
- : mStatistics(false)
- , start(CLOCK_MONOTONIC) {
- log_id_for_each(i) {
- mSizes[i] = 0;
- mElements[i] = 0;
- }
-}
-
-void LogStatistics::add(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
- mSizes[log_id] += size;
- ++mElements[log_id];
- if (!mStatistics) {
- return;
- }
- id(log_id).add(size, uid, pid);
-}
-
-void LogStatistics::subtract(unsigned short size,
- log_id_t log_id, uid_t uid, pid_t pid) {
- mSizes[log_id] -= size;
- --mElements[log_id];
- if (!mStatistics) {
- return;
- }
- id(log_id).subtract(size, uid, pid);
-}
-
-size_t LogStatistics::sizes(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).sizes(uid, pid);
- }
- size_t sizes = 0;
- log_id_for_each(i) {
- sizes += id(i).sizes(uid, pid);
- }
- return sizes;
-}
-size_t LogStatistics::elements(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).elements(uid, pid);
- }
- size_t elements = 0;
- log_id_for_each(i) {
- elements += id(i).elements(uid, pid);
- }
- return elements;
+ // No one
+ return NULL;
}
-size_t LogStatistics::sizesTotal(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).sizesTotal(uid, pid);
- }
- size_t sizes = 0;
- log_id_for_each(i) {
- sizes += id(i).sizesTotal(uid, pid);
- }
- return sizes;
-}
+static void format_line(android::String8 &output,
+ android::String8 &name, android::String8 &size) {
+ static const size_t total_len = 70;
-size_t LogStatistics::elementsTotal(log_id_t log_id, uid_t uid, pid_t pid) {
- if (log_id != log_id_all) {
- return id(log_id).elementsTotal(uid, pid);
- }
- size_t elements = 0;
- log_id_for_each(i) {
- elements += id(i).elementsTotal(uid, pid);
- }
- return elements;
+ output.appendFormat("%s%*s\n", name.string(),
+ (int)std::max(total_len - name.length() - 1, size.length() + 1)
+ size.string());
}
-void LogStatistics::format(char **buf,
- uid_t uid, unsigned int logMask, log_time oldest) {
- static const unsigned short spaces_current = 13;
+void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
static const unsigned short spaces_total = 19;
if (*buf) {
@@ -476,368 +166,142 @@ void LogStatistics::format(char **buf,
*buf = NULL;
}
- android::String8 string(" span -> size/num");
+ // Report on total logging, current and for all time
+
+ android::String8 output("size/num");
size_t oldLength;
- short spaces = 2;
+ short spaces = 1;
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- oldLength = string.length();
+ oldLength = output.length();
if (spaces < 0) {
spaces = 0;
}
- string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
- spaces += spaces_total + oldLength - string.length();
+ output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+ spaces += spaces_total + oldLength - output.length();
+ }
- LidStatistics &l = id(i);
- l.sort();
+ spaces = 4;
+ output.appendFormat("\nTotal");
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- (*iu)->sort();
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
+ continue;
}
- }
-
- spaces = 1;
- log_time t(CLOCK_MONOTONIC);
- unsigned long long d;
- if (mStatistics) {
- d = t.nsec() - start.nsec();
- string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
- d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
- (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
-
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
- }
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- sizesTotal(i), elementsTotal(i));
- spaces += spaces_total + oldLength - string.length();
+ oldLength = output.length();
+ if (spaces < 0) {
+ spaces = 0;
}
- spaces = 1;
+ output.appendFormat("%*s%zu/%zu", spaces, "",
+ sizesTotal(id), elementsTotal(id));
+ spaces += spaces_total + oldLength - output.length();
}
- d = t.nsec() - oldest.nsec();
- string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
- d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
- (d / NS_PER_SEC) % 60, d % NS_PER_SEC);
+ spaces = 6;
+ output.appendFormat("\nNow");
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- size_t els = elements(i);
+ size_t els = elements(id);
if (els) {
- oldLength = string.length();
+ oldLength = output.length();
if (spaces < 0) {
spaces = 0;
}
- string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
- spaces -= string.length() - oldLength;
+ output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+ spaces -= output.length() - oldLength;
}
spaces += spaces_total;
}
- // Construct list of worst spammers by Pid
- static const unsigned char num_spammers = 10;
- bool header = false;
+ // Report on Chattiest
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
+ // Chattiest by application (UID)
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) {
continue;
}
- PidStatisticsCollection pids;
- pids.clear();
-
- LidStatistics &l = id(i);
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- UidStatistics &u = *(*iu);
- PidStatisticsCollection::iterator ip;
- for (ip = u.begin(); ip != u.end(); ++ip) {
- PidStatistics *p = (*ip);
- if (p->getPid() == p->gone) {
- break;
- }
-
- size_t mySizes = p->sizes();
-
- PidStatisticsCollection::iterator q;
- unsigned char num = 0;
- for (q = pids.begin(); q != pids.end(); ++q) {
- if (mySizes > (*q)->sizes()) {
- pids.insert(q, p);
- break;
- }
- // do we need to traverse deeper in the list?
- if (++num > num_spammers) {
- break;
- }
- }
- if (q == pids.end()) {
- pids.push_back(p);
- }
- }
- }
+ static const size_t maximum_sorted_entries = 32;
+ const UidEntry **sorted = sort(maximum_sorted_entries, id);
- size_t threshold = sizes(i);
- if (threshold < 65536) {
- threshold = 65536;
+ if (!sorted) {
+ continue;
}
- threshold /= 100;
-
- PidStatisticsCollection::iterator pt = pids.begin();
- for(int line = 0;
- (pt != pids.end()) && (line < num_spammers);
- ++line, pt = pids.erase(pt)) {
- PidStatistics *p = *pt;
+ bool print = false;
+ for(size_t index = 0; index < maximum_sorted_entries; ++index) {
+ const UidEntry *entry = sorted[index];
- size_t sizes = p->sizes();
- if (sizes < threshold) {
+ if (!entry) {
break;
}
- char *name = p->getName();
- pid_t pid = p->getPid();
- if (!name || !*name) {
- name = pidToName(pid);
- if (name) {
- if (*name) {
- p->setName(name);
- } else {
- free(name);
- name = NULL;
- }
- }
- }
-
- if (!header) {
- string.appendFormat("\n\nChattiest clients:\n"
- "log id %-*s PID[?] name",
- spaces_total, "size/total");
- header = true;
- }
-
- size_t sizesTotal = p->sizesTotal();
-
- android::String8 sz("");
- if (sizes == sizesTotal) {
- sz.appendFormat("%zu", sizes);
- } else {
- sz.appendFormat("%zu/%zu", sizes, sizesTotal);
- }
-
- android::String8 pd("");
- pd.appendFormat("%u%c", pid, p->pidGone() ? '?' : ' ');
-
- string.appendFormat("\n%-7s%-*s %-7s%s",
- line ? "" : android_log_id_to_name(i),
- spaces_total, sz.string(), pd.string(),
- name ? name : "");
- }
-
- pids.clear();
- }
-
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
- }
-
- header = false;
- bool first = true;
-
- UidStatisticsCollection::iterator ut;
- for(ut = id(i).begin(); ut != id(i).end(); ++ut) {
- UidStatistics *up = *ut;
- if ((uid != AID_ROOT) && (uid != up->getUid())) {
- continue;
+ size_t sizes = entry->getSizes();
+ if (sizes < (65536/100)) {
+ break;
}
- PidStatisticsCollection::iterator pt = up->begin();
- if (pt == up->end()) {
+ uid_t u = entry->getKey();
+ if ((uid != AID_ROOT) && (u != uid)) {
continue;
}
- android::String8 intermediate;
-
- if (!header) {
- // header below tuned to match spaces_total and spaces_current
- spaces = 0;
- intermediate = string.format("%s: UID/PID Total size/num",
- android_log_id_to_name(i));
- string.appendFormat("\n\n%-31sNow "
- "UID/PID[?] Total Now",
- intermediate.string());
- intermediate.clear();
- header = true;
- }
-
- bool oneline = ++pt == up->end();
- --pt;
-
- if (!oneline) {
- first = true;
- } else if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- spaces = 0;
-
- uid_t u = up->getUid();
- PidStatistics *pp = *pt;
- pid_t p = pp->getPid();
-
- if (!oneline) {
- intermediate = string.format("%d", u);
- } else if (p == PidStatistics::gone) {
- intermediate = string.format("%d/?", u);
- } else if (pp->pidGone()) {
- intermediate = string.format("%d/%d?", u, p);
- } else {
- intermediate = string.format("%d/%d", u, p);
- }
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- size_t elsTotal = up->elementsTotal();
- oldLength = string.length();
- string.appendFormat("%zu/%zu", up->sizesTotal(), elsTotal);
- spaces += spaces_total + oldLength - string.length();
-
- size_t els = up->elements();
- if (els == elsTotal) {
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s=", spaces, "");
- spaces = -1;
- } else if (els) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
+ if (!print) {
+ if (uid == AID_ROOT) {
+ output.appendFormat(
+ "\n\nChattiest UIDs in %s:\n",
+ android_log_id_to_name(id));
+ android::String8 name("UID");
+ android::String8 size("Size");
+ format_line(output, name, size);
+ } else {
+ output.appendFormat(
+ "\n\nLogging for your UID in %s:\n",
+ android_log_id_to_name(id));
}
- string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
- spaces -= string.length() - oldLength;
+ print = true;
}
- spaces += spaces_current;
-
- first = !first;
- if (oneline) {
- continue;
+ android::String8 name("");
+ name.appendFormat("%u", u);
+ char *n = uidToName(u);
+ if (n) {
+ name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+ free(n);
}
- size_t gone_szs = 0;
- size_t gone_els = 0;
-
- for(; pt != up->end(); ++pt) {
- pp = *pt;
- p = pp->getPid();
-
- // If a PID no longer has any current logs, and is not
- // active anymore, skip & report totals for gone.
- elsTotal = pp->elementsTotal();
- size_t szsTotal = pp->sizesTotal();
- if (p == pp->gone) {
- gone_szs += szsTotal;
- gone_els += elsTotal;
- continue;
- }
- els = pp->elements();
- bool gone = pp->pidGone();
- if (gone && (els == 0)) {
- // ToDo: garbage collection: move this statistical bucket
- // from its current UID/PID to UID/? (races and
- // wrap around are our achilles heel). Below is
- // merely lipservice to catch PIDs that were still
- // around when the stats were pruned to zero.
- gone_szs += szsTotal;
- gone_els += elsTotal;
- continue;
- }
-
- if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
- spaces = 0;
-
- intermediate = string.format(gone ? "%d/%d?" : "%d/%d", u, p);
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- oldLength = string.length();
- string.appendFormat("%zu/%zu", szsTotal, elsTotal);
- spaces += spaces_total + oldLength - string.length();
-
- if (els == elsTotal) {
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s=", spaces, "");
- spaces = -1;
- } else if (els) {
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- pp->sizes(), els);
- spaces -= string.length() - oldLength;
- }
- spaces += spaces_current;
+ android::String8 size("");
+ size.appendFormat("%zu", sizes);
- first = !first;
- }
-
- if (gone_els) {
- if (!first && (spaces > 0)) {
- string.appendFormat("%*s", spaces, "");
- }
-
- intermediate = string.format("%d/?", u);
- string.appendFormat(first ? "\n%-12s" : "%-12s",
- intermediate.string());
- intermediate.clear();
-
- spaces = spaces_total + spaces_current;
-
- oldLength = string.length();
- string.appendFormat("%zu/%zu", gone_szs, gone_els);
- spaces -= string.length() - oldLength;
-
- first = !first;
- }
+ format_line(output, name, size);
}
+
+ delete [] sorted;
}
- *buf = strdup(string.string());
+ *buf = strdup(output.string());
}
uid_t LogStatistics::pidToUid(pid_t pid) {
- log_id_for_each(i) {
- LidStatistics &l = id(i);
- UidStatisticsCollection::iterator iu;
- for (iu = l.begin(); iu != l.end(); ++iu) {
- UidStatistics &u = *(*iu);
- PidStatisticsCollection::iterator ip;
- for (ip = u.begin(); ip != u.end(); ++ip) {
- if ((*ip)->getPid() == pid) {
- return u.getUid();
- }
+ char buffer[512];
+ snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
+ FILE *fp = fopen(buffer, "r");
+ if (fp) {
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ int uid;
+ if (sscanf(buffer, "Groups: %d", &uid) == 1) {
+ fclose(fp);
+ return uid;
}
}
+ fclose(fp);
}
return getuid(); // associate this with the logger
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f892cd0..d5b8762 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -20,175 +20,60 @@
#include <sys/types.h>
#include <log/log.h>
-#include <log/log_read.h>
-#include <utils/List.h>
+#include <utils/BasicHashtable.h>
+
+#include "LogBufferElement.h"
#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 PidStatistics {
- const pid_t pid;
-
- // Total
- size_t mSizesTotal;
- size_t mElementsTotal;
- // Current
- size_t mSizes;
- size_t mElements;
-
- char *name;
- bool mGone;
-
-public:
- static const pid_t gone = (pid_t) -1;
-
- PidStatistics(pid_t pid, char *name = NULL);
- PidStatistics(const PidStatistics &copy);
- ~PidStatistics();
-
- pid_t getPid() const { return pid; }
- bool pidGone();
- char *getName() const { return name; }
- void setName(char *name);
-
- void add(unsigned short size);
- bool subtract(unsigned short size); // returns true if stats and PID gone
- void addTotal(size_t size, size_t element);
-
- size_t sizes() const { return mSizes; }
- size_t elements() const { return mElements; }
-
- size_t sizesTotal() const { return mSizesTotal; }
- size_t elementsTotal() const { return mElementsTotal; }
-
- // helper
- static char *pidToName(pid_t pid);
-};
-
-typedef android::List<PidStatistics *> PidStatisticsCollection;
-
-class UidStatistics {
+struct UidEntry {
const uid_t uid;
+ size_t size;
- PidStatisticsCollection Pids;
-
- void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
- { Pids.insert(i, p); }
- void push_back(PidStatistics *p) { Pids.push_back(p); }
-
- size_t mSizes;
- size_t mElements;
-
-public:
- UidStatistics(uid_t uid);
- ~UidStatistics();
-
- PidStatisticsCollection::iterator begin() { return Pids.begin(); }
- PidStatisticsCollection::iterator end() { return Pids.end(); }
- PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i)
- { return Pids.erase(i); }
-
- uid_t getUid() { return uid; }
-
- void add(unsigned short size, pid_t pid);
- void subtract(unsigned short size, pid_t pid);
- void sort();
+ UidEntry(uid_t uid):uid(uid),size(0) { }
- static const pid_t pid_all = (pid_t) -1;
-
- // fast track current value
- size_t sizes() const { return mSizes; };
- size_t elements() const { return mElements; };
-
- // statistical track
- size_t sizes(pid_t pid);
- size_t elements(pid_t pid);
-
- size_t sizesTotal(pid_t pid = pid_all);
- size_t elementsTotal(pid_t pid = pid_all);
-
- // helper
- static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
-};
-
-typedef android::List<UidStatistics *> UidStatisticsCollection;
-
-class LidStatistics {
- UidStatisticsCollection Uids;
-
-public:
- LidStatistics();
- ~LidStatistics();
-
- UidStatisticsCollection::iterator begin() { return Uids.begin(); }
- UidStatisticsCollection::iterator end() { return Uids.end(); }
-
- void add(unsigned short size, uid_t uid, pid_t pid);
- void subtract(unsigned short size, uid_t uid, pid_t pid);
- void sort();
-
- static const pid_t pid_all = (pid_t) -1;
- static const uid_t uid_all = (uid_t) -1;
-
- size_t sizes(uid_t uid = uid_all, pid_t pid = pid_all);
- size_t elements(uid_t uid = uid_all, pid_t pid = pid_all);
-
- size_t sizesTotal(uid_t uid = uid_all, pid_t pid = pid_all);
- size_t elementsTotal(uid_t uid = uid_all, pid_t pid = pid_all);
+ inline const uid_t&getKey() const { return uid; }
+ size_t getSizes() const { return size; }
+ inline void add(size_t s) { size += s; }
+ inline bool subtract(size_t s) { size -= s; return !size; }
};
// Log Statistics
class LogStatistics {
- LidStatistics LogIds[LOG_ID_MAX];
-
size_t mSizes[LOG_ID_MAX];
size_t mElements[LOG_ID_MAX];
+ size_t mSizesTotal[LOG_ID_MAX];
+ size_t mElementsTotal[LOG_ID_MAX];
- bool mStatistics;
-
- static const unsigned short mBuckets[14];
- log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
+ // uid to size list
+ typedef android::BasicHashtable<uid_t, UidEntry> uidTable_t;
+ uidTable_t uidTable[LOG_ID_MAX];
public:
- const log_time start;
-
LogStatistics();
- LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
+ void enableStatistics() { }
- void enableStatistics() { mStatistics = true; }
+ void add(LogBufferElement *entry);
+ void subtract(LogBufferElement *entry);
- 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);
- void sort();
+ // Caller must delete array
+ const UidEntry **sort(size_t n, log_id i);
// fast track current value by id only
size_t sizes(log_id_t id) const { return mSizes[id]; }
size_t elements(log_id_t id) const { return mElements[id]; }
-
- // statistical track
- static const log_id_t log_id_all = (log_id_t) -1;
- static const uid_t uid_all = (uid_t) -1;
- static const pid_t pid_all = (pid_t) -1;
-
- size_t sizes(log_id_t id, uid_t uid, pid_t pid = pid_all);
- size_t elements(log_id_t id, uid_t uid, pid_t pid = pid_all);
- size_t sizes() { return sizes(log_id_all, uid_all); }
- size_t elements() { return elements(log_id_all, uid_all); }
-
- size_t sizesTotal(log_id_t id = log_id_all,
- uid_t uid = uid_all,
- pid_t pid = pid_all);
- size_t elementsTotal(log_id_t id = log_id_all,
- uid_t uid = uid_all,
- pid_t pid = pid_all);
+ size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
+ size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
// *strp = malloc, balance with free
- void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
+ void format(char **strp, uid_t uid, unsigned int logMask);
// helper
- static char *pidToName(pid_t pid) { return PidStatistics::pidToName(pid); }
+ char *pidToName(pid_t pid);
uid_t pidToUid(pid_t pid);
+ char *uidToName(uid_t uid);
};
#endif // _LOGD_LOG_STATISTICS_H__
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 769d651..5f60801 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -61,7 +61,9 @@ public:
int init(char *str);
bool naughty(LogBufferElement *element);
+ bool naughty(void) { return !mNaughty.empty(); }
bool nice(LogBufferElement *element);
+ bool nice(void) { return !mNice.empty(); }
bool worstUidEnabled() const { return mWorstUidEnabled; }
// *strp is malloc'd, use free to release