logd: optimize statistics
- Go back to basic requirements - Simplify - use hash tables to minimize memory impact Bug: 19608965 Change-Id: If7becb34354d6415e5c387ecea7d4109a15259c8
This commit is contained in:
parent
ca87790cdc
commit
97c1c2beee
|
@ -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);
|
||||
}
|
||||
|
||||
it = mLogElements.erase(it);
|
||||
stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
|
||||
delete e;
|
||||
pruneRows--;
|
||||
} else {
|
||||
it++;
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
it = mLogElements.erase(it);
|
||||
stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
|
||||
delete e;
|
||||
pruneRows--;
|
||||
} else {
|
||||
it++;
|
||||
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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__
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 ©)
|
||||
: 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 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);
|
||||
} else {
|
||||
push_back(p);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
LidStatistics::LidStatistics() {
|
||||
Uids.clear();
|
||||
}
|
||||
|
||||
LidStatistics::~LidStatistics() {
|
||||
UidStatisticsCollection::iterator it;
|
||||
for (it = begin(); it != end();) {
|
||||
delete (*it);
|
||||
it = Uids.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
void LogStatistics::add(LogBufferElement *e) {
|
||||
log_id_t log_id = e->getLogId();
|
||||
unsigned short size = e->getMsgLen();
|
||||
mSizes[log_id] += size;
|
||||
++mElements[log_id];
|
||||
if (!mStatistics) {
|
||||
return;
|
||||
|
||||
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 {
|
||||
UidEntry &entry = table.editEntryAt(index);
|
||||
entry.add(size);
|
||||
}
|
||||
id(log_id).add(size, uid, pid);
|
||||
|
||||
mSizesTotal[log_id] += size;
|
||||
++mElementsTotal[log_id];
|
||||
}
|
||||
|
||||
void LogStatistics::subtract(unsigned short size,
|
||||
log_id_t log_id, uid_t uid, pid_t pid) {
|
||||
void LogStatistics::subtract(LogBufferElement *e) {
|
||||
log_id_t log_id = e->getLogId();
|
||||
unsigned short size = e->getMsgLen();
|
||||
mSizes[log_id] -= size;
|
||||
--mElements[log_id];
|
||||
if (!mStatistics) {
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
// caller must own and delete UidEntry array
|
||||
const UidEntry **LogStatistics::sort(size_t n, log_id id) {
|
||||
if (!n) {
|
||||
return NULL;
|
||||
}
|
||||
size_t sizes = 0;
|
||||
log_id_for_each(i) {
|
||||
sizes += id(i).sizes(uid, pid);
|
||||
|
||||
const UidEntry **retval = new const UidEntry* [n];
|
||||
memset(retval, 0, sizeof(*retval) * 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 sizes;
|
||||
return retval;
|
||||
}
|
||||
|
||||
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);
|
||||
// caller must own and free character string
|
||||
char *LogStatistics::uidToName(uid_t uid) {
|
||||
// Local hard coded favourites
|
||||
if (uid == AID_LOGD) {
|
||||
return strdup("auditd");
|
||||
}
|
||||
size_t elements = 0;
|
||||
log_id_for_each(i) {
|
||||
elements += id(i).elements(uid, pid);
|
||||
|
||||
// Android hard coded
|
||||
const struct android_id_info *info = android_ids;
|
||||
|
||||
for (size_t i = 0; i < android_id_count; ++i) {
|
||||
if (info->aid == uid) {
|
||||
return strdup(info->name);
|
||||
}
|
||||
++info;
|
||||
}
|
||||
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;
|
||||
|
||||
output.appendFormat("%s%*s\n", name.string(),
|
||||
(int)std::max(total_len - name.length() - 1, size.length() + 1)
|
||||
size.string());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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");
|
||||
size_t oldLength;
|
||||
short spaces = 2;
|
||||
// Report on total logging, current and for all time
|
||||
|
||||
log_id_for_each(i) {
|
||||
if (!(logMask & (1 << i))) {
|
||||
android::String8 output("size/num");
|
||||
size_t oldLength;
|
||||
short spaces = 1;
|
||||
|
||||
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();
|
||||
|
||||
LidStatistics &l = id(i);
|
||||
l.sort();
|
||||
|
||||
UidStatisticsCollection::iterator iu;
|
||||
for (iu = l.begin(); iu != l.end(); ++iu) {
|
||||
(*iu)->sort();
|
||||
}
|
||||
output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
|
||||
spaces += spaces_total + oldLength - output.length();
|
||||
}
|
||||
|
||||
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);
|
||||
spaces = 4;
|
||||
output.appendFormat("\nTotal");
|
||||
|
||||
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();
|
||||
log_id_for_each(id) {
|
||||
if (!(logMask & (1 << id))) {
|
||||
continue;
|
||||
}
|
||||
spaces = 1;
|
||||
oldLength = output.length();
|
||||
if (spaces < 0) {
|
||||
spaces = 0;
|
||||
}
|
||||
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();
|
||||
static const size_t maximum_sorted_entries = 32;
|
||||
const UidEntry **sorted = sort(maximum_sorted_entries, id);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (!sorted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t threshold = sizes(i);
|
||||
if (threshold < 65536) {
|
||||
threshold = 65536;
|
||||
}
|
||||
threshold /= 100;
|
||||
bool print = false;
|
||||
for(size_t index = 0; index < maximum_sorted_entries; ++index) {
|
||||
const UidEntry *entry = sorted[index];
|
||||
|
||||
PidStatisticsCollection::iterator pt = pids.begin();
|
||||
|
||||
for(int line = 0;
|
||||
(pt != pids.end()) && (line < num_spammers);
|
||||
++line, pt = pids.erase(pt)) {
|
||||
PidStatistics *p = *pt;
|
||||
|
||||
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;
|
||||
}
|
||||
size_t sizes = entry->getSizes();
|
||||
if (sizes < (65536/100)) {
|
||||
break;
|
||||
}
|
||||
|
||||
uid_t u = entry->getKey();
|
||||
if ((uid != AID_ROOT) && (u != uid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
print = true;
|
||||
}
|
||||
|
||||
if (!header) {
|
||||
string.appendFormat("\n\nChattiest clients:\n"
|
||||
"log id %-*s PID[?] name",
|
||||
spaces_total, "size/total");
|
||||
header = true;
|
||||
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 sizesTotal = p->sizesTotal();
|
||||
android::String8 size("");
|
||||
size.appendFormat("%zu", sizes);
|
||||
|
||||
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 : "");
|
||||
format_line(output, name, size);
|
||||
}
|
||||
|
||||
pids.clear();
|
||||
delete [] sorted;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
PidStatisticsCollection::iterator pt = up->begin();
|
||||
if (pt == up->end()) {
|
||||
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;
|
||||
}
|
||||
string.appendFormat("%*s%zu/%zu", spaces, "", up->sizes(), els);
|
||||
spaces -= string.length() - oldLength;
|
||||
}
|
||||
spaces += spaces_current;
|
||||
|
||||
first = !first;
|
||||
|
||||
if (oneline) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*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
|
||||
}
|
||||
|
|
|
@ -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 ©);
|
||||
~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;
|
||||
UidEntry(uid_t uid):uid(uid),size(0) { }
|
||||
|
||||
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();
|
||||
|
||||
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__
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue