2014-02-07 06:48:50 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2014-04-07 22:05:40 +08:00
|
|
|
#include <fcntl.h>
|
2016-04-08 02:06:31 +08:00
|
|
|
#include <pwd.h>
|
2015-03-11 04:51:35 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2016-04-08 02:06:31 +08:00
|
|
|
#include <sys/types.h>
|
2015-03-11 04:51:35 +08:00
|
|
|
#include <unistd.h>
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2016-10-06 03:34:37 +08:00
|
|
|
#include <list>
|
|
|
|
|
2016-10-01 04:30:33 +08:00
|
|
|
#include <android/log.h>
|
2014-02-07 06:48:50 +08:00
|
|
|
|
|
|
|
#include "LogStatistics.h"
|
|
|
|
|
2016-09-13 01:29:17 +08:00
|
|
|
size_t LogStatistics::SizesTotal;
|
|
|
|
|
2015-05-13 06:21:31 +08:00
|
|
|
LogStatistics::LogStatistics() : enable(false) {
|
2015-03-11 04:51:35 +08:00
|
|
|
log_id_for_each(id) {
|
|
|
|
mSizes[id] = 0;
|
|
|
|
mElements[id] = 0;
|
2015-09-30 22:40:09 +08:00
|
|
|
mDroppedElements[id] = 0;
|
2015-03-11 04:51:35 +08:00
|
|
|
mSizesTotal[id] = 0;
|
|
|
|
mElementsTotal[id] = 0;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
namespace android {
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
size_t sizesTotal() {
|
|
|
|
return LogStatistics::sizesTotal();
|
|
|
|
}
|
2016-09-13 01:29:17 +08:00
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// caller must own and free character string
|
2017-03-11 06:31:54 +08:00
|
|
|
char* pidToName(pid_t pid) {
|
|
|
|
char* retval = NULL;
|
|
|
|
if (pid == 0) { // special case from auditd/klogd for kernel
|
2014-10-15 23:49:39 +08:00
|
|
|
retval = strdup("logd");
|
2015-03-11 04:51:35 +08:00
|
|
|
} else {
|
2014-04-07 22:05:40 +08:00
|
|
|
char buffer[512];
|
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
|
|
|
|
int fd = open(buffer, O_RDONLY);
|
|
|
|
if (fd >= 0) {
|
|
|
|
ssize_t ret = read(fd, buffer, sizeof(buffer));
|
|
|
|
if (ret > 0) {
|
2017-03-11 06:31:54 +08:00
|
|
|
buffer[sizeof(buffer) - 1] = '\0';
|
2014-04-07 22:05:40 +08:00
|
|
|
// frameworks intermediate state
|
2016-12-03 02:08:48 +08:00
|
|
|
if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
|
2014-04-07 22:05:40 +08:00
|
|
|
retval = strdup(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
void LogStatistics::add(LogBufferElement* element) {
|
2015-08-22 07:44:30 +08:00
|
|
|
log_id_t log_id = element->getLogId();
|
|
|
|
unsigned short size = element->getMsgLen();
|
2015-03-11 04:51:35 +08:00
|
|
|
mSizes[log_id] += size;
|
|
|
|
++mElements[log_id];
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2016-12-14 02:31:29 +08:00
|
|
|
if (element->getDropped()) {
|
|
|
|
++mDroppedElements[log_id];
|
|
|
|
} else {
|
|
|
|
// When caller adding a chatty entry, they will have already
|
|
|
|
// called add() and subtract() for each entry as they are
|
|
|
|
// evaluated and trimmed, thus recording size and number of
|
|
|
|
// elements, but we must recognize the manufactured dropped
|
|
|
|
// entry as not contributing to the lifetime totals.
|
|
|
|
mSizesTotal[log_id] += size;
|
2016-09-13 01:29:17 +08:00
|
|
|
SizesTotal += size;
|
2016-12-14 02:31:29 +08:00
|
|
|
++mElementsTotal[log_id];
|
|
|
|
}
|
2015-03-16 23:26:05 +08:00
|
|
|
|
2014-10-15 23:49:39 +08:00
|
|
|
if (log_id == LOG_ID_KERNEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
uidTable[log_id].add(element->getUid(), element);
|
2015-08-28 23:02:59 +08:00
|
|
|
if (element->getUid() == AID_SYSTEM) {
|
|
|
|
pidSystemTable[log_id].add(element->getPid(), element);
|
|
|
|
}
|
2014-10-15 23:49:39 +08:00
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
if (!enable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
pidTable.add(element->getPid(), element);
|
|
|
|
tidTable.add(element->getTid(), element);
|
2015-04-14 05:24:45 +08:00
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
uint32_t tag = element->getTag();
|
2015-04-14 05:24:45 +08:00
|
|
|
if (tag) {
|
2015-12-05 02:59:45 +08:00
|
|
|
if (log_id == LOG_ID_SECURITY) {
|
|
|
|
securityTagTable.add(tag, element);
|
|
|
|
} else {
|
|
|
|
tagTable.add(tag, element);
|
|
|
|
}
|
2015-04-14 05:24:45 +08:00
|
|
|
}
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
void LogStatistics::subtract(LogBufferElement* element) {
|
2015-08-22 07:44:30 +08:00
|
|
|
log_id_t log_id = element->getLogId();
|
|
|
|
unsigned short size = element->getMsgLen();
|
2015-03-11 04:51:35 +08:00
|
|
|
mSizes[log_id] -= size;
|
|
|
|
--mElements[log_id];
|
2015-09-30 22:40:09 +08:00
|
|
|
if (element->getDropped()) {
|
|
|
|
--mDroppedElements[log_id];
|
|
|
|
}
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2014-10-15 23:49:39 +08:00
|
|
|
if (log_id == LOG_ID_KERNEL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
uidTable[log_id].subtract(element->getUid(), element);
|
2015-08-28 23:02:59 +08:00
|
|
|
if (element->getUid() == AID_SYSTEM) {
|
|
|
|
pidSystemTable[log_id].subtract(element->getPid(), element);
|
|
|
|
}
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
if (!enable) {
|
|
|
|
return;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
pidTable.subtract(element->getPid(), element);
|
|
|
|
tidTable.subtract(element->getTid(), element);
|
2015-04-14 05:24:45 +08:00
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
uint32_t tag = element->getTag();
|
2015-04-14 05:24:45 +08:00
|
|
|
if (tag) {
|
2015-12-05 02:59:45 +08:00
|
|
|
if (log_id == LOG_ID_SECURITY) {
|
|
|
|
securityTagTable.subtract(tag, element);
|
|
|
|
} else {
|
|
|
|
tagTable.subtract(tag, element);
|
|
|
|
}
|
2015-04-14 05:24:45 +08:00
|
|
|
}
|
2014-04-05 07:35:59 +08:00
|
|
|
}
|
|
|
|
|
2015-03-17 03:04:09 +08:00
|
|
|
// Atomically set an entry to drop
|
|
|
|
// entry->setDropped(1) must follow this call, caller should do this explicitly.
|
2017-03-11 06:31:54 +08:00
|
|
|
void LogStatistics::drop(LogBufferElement* element) {
|
2015-08-22 07:44:30 +08:00
|
|
|
log_id_t log_id = element->getLogId();
|
|
|
|
unsigned short size = element->getMsgLen();
|
2015-03-17 03:04:09 +08:00
|
|
|
mSizes[log_id] -= size;
|
2015-09-30 22:40:09 +08:00
|
|
|
++mDroppedElements[log_id];
|
2015-03-17 03:04:09 +08:00
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
uidTable[log_id].drop(element->getUid(), element);
|
2015-08-28 23:02:59 +08:00
|
|
|
if (element->getUid() == AID_SYSTEM) {
|
|
|
|
pidSystemTable[log_id].drop(element->getPid(), element);
|
|
|
|
}
|
2015-03-17 03:04:09 +08:00
|
|
|
|
|
|
|
if (!enable) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
pidTable.drop(element->getPid(), element);
|
|
|
|
tidTable.drop(element->getTid(), element);
|
2016-07-15 06:34:30 +08:00
|
|
|
|
|
|
|
uint32_t tag = element->getTag();
|
|
|
|
if (tag) {
|
|
|
|
if (log_id == LOG_ID_SECURITY) {
|
|
|
|
securityTagTable.drop(tag, element);
|
|
|
|
} else {
|
|
|
|
tagTable.drop(tag, element);
|
|
|
|
}
|
|
|
|
}
|
2015-03-17 03:04:09 +08:00
|
|
|
}
|
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// caller must own and free character string
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* LogStatistics::uidToName(uid_t uid) const {
|
2015-03-11 04:51:35 +08:00
|
|
|
// Local hard coded favourites
|
|
|
|
if (uid == AID_LOGD) {
|
|
|
|
return strdup("auditd");
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
|
2016-04-08 02:06:31 +08:00
|
|
|
// Android system
|
|
|
|
if (uid < AID_APP) {
|
|
|
|
// in bionic, thread safe as long as we copy the results
|
2017-03-11 06:31:54 +08:00
|
|
|
struct passwd* pwd = getpwuid(uid);
|
2016-04-08 02:06:31 +08:00
|
|
|
if (pwd) {
|
|
|
|
return strdup(pwd->pw_name);
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
// Parse /data/system/packages.list
|
2016-12-14 02:55:19 +08:00
|
|
|
uid_t userId = uid % AID_USER_OFFSET;
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* name = android::uidToName(userId);
|
2015-04-30 03:48:45 +08:00
|
|
|
if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
|
|
|
|
name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
|
|
|
|
}
|
2015-03-16 23:26:05 +08:00
|
|
|
if (name) {
|
|
|
|
return name;
|
|
|
|
}
|
2015-03-16 23:26:05 +08:00
|
|
|
|
2016-04-08 02:06:31 +08:00
|
|
|
// Android application
|
|
|
|
if (uid >= AID_APP) {
|
2017-03-11 06:31:54 +08:00
|
|
|
struct passwd* pwd = getpwuid(uid);
|
2016-04-08 02:06:31 +08:00
|
|
|
if (pwd) {
|
|
|
|
return strdup(pwd->pw_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
// report uid -> pid(s) -> pidToName if unique
|
2017-03-11 06:31:54 +08:00
|
|
|
for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
|
|
|
|
++it) {
|
|
|
|
const PidEntry& entry = it->second;
|
2015-03-16 23:26:05 +08:00
|
|
|
|
|
|
|
if (entry.getUid() == uid) {
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* nameTmp = entry.getName();
|
2015-03-16 23:26:05 +08:00
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
if (nameTmp) {
|
2015-03-16 23:26:05 +08:00
|
|
|
if (!name) {
|
2015-08-22 07:44:30 +08:00
|
|
|
name = strdup(nameTmp);
|
2016-12-03 02:08:48 +08:00
|
|
|
} else if (fastcmp<strcmp>(name, nameTmp)) {
|
2017-03-11 06:31:54 +08:00
|
|
|
free(const_cast<char*>(name));
|
2015-04-30 03:48:45 +08:00
|
|
|
name = NULL;
|
|
|
|
break;
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// No one
|
2015-03-16 23:26:05 +08:00
|
|
|
return name;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
bool isprune = worstUidEnabledForLogid(id);
|
2017-03-11 06:31:54 +08:00
|
|
|
return formatLine(android::base::StringPrintf(name.c_str(),
|
|
|
|
android_log_id_to_name(id)),
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string("Size"),
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string(isprune ? "+/- Pruned" : "")) +
|
|
|
|
formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string(isprune ? "NUM" : ""));
|
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string UidEntry::format(const LogStatistics& stat, log_id_t id) const {
|
2015-12-18 01:58:43 +08:00
|
|
|
uid_t uid = getUid();
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string name = android::base::StringPrintf("%u", uid);
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* nameTmp = stat.uidToName(uid);
|
2015-08-22 07:44:30 +08:00
|
|
|
if (nameTmp) {
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", nameTmp);
|
|
|
|
free(const_cast<char*>(nameTmp));
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string size = android::base::StringPrintf("%zu", getSizes());
|
|
|
|
|
|
|
|
std::string pruned = "";
|
2015-08-25 02:08:00 +08:00
|
|
|
if (worstUidEnabledForLogid(id)) {
|
|
|
|
size_t totalDropped = 0;
|
2017-03-11 06:31:54 +08:00
|
|
|
for (LogStatistics::uidTable_t::const_iterator it =
|
|
|
|
stat.uidTable[id].begin();
|
|
|
|
it != stat.uidTable[id].end(); ++it) {
|
2015-08-25 02:08:00 +08:00
|
|
|
totalDropped += it->second.getDropped();
|
|
|
|
}
|
|
|
|
size_t sizes = stat.sizes(id);
|
|
|
|
size_t totalSize = stat.sizesTotal(id);
|
|
|
|
size_t totalElements = stat.elementsTotal(id);
|
2017-03-11 06:31:54 +08:00
|
|
|
float totalVirtualSize =
|
|
|
|
(float)sizes + (float)totalDropped * totalSize / totalElements;
|
2015-08-25 02:08:00 +08:00
|
|
|
size_t entrySize = getSizes();
|
|
|
|
float virtualEntrySize = entrySize;
|
|
|
|
int realPermille = virtualEntrySize * 1000.0 / sizes;
|
|
|
|
size_t dropped = getDropped();
|
|
|
|
if (dropped) {
|
|
|
|
pruned = android::base::StringPrintf("%zu", dropped);
|
|
|
|
virtualEntrySize += (float)dropped * totalSize / totalElements;
|
|
|
|
}
|
|
|
|
int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
|
2017-03-11 06:31:54 +08:00
|
|
|
int permille =
|
|
|
|
(realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
|
2015-08-25 02:08:00 +08:00
|
|
|
if ((permille < -1) || (1 < permille)) {
|
|
|
|
std::string change;
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* units = "%";
|
|
|
|
const char* prefix = (permille > 0) ? "+" : "";
|
2015-08-25 02:08:00 +08:00
|
|
|
|
|
|
|
if (permille > 999) {
|
2017-03-11 06:31:54 +08:00
|
|
|
permille = (permille + 1000) / 100; // Now tenths fold
|
2015-08-25 02:08:00 +08:00
|
|
|
units = "X";
|
|
|
|
prefix = "";
|
|
|
|
}
|
|
|
|
if ((-99 < permille) && (permille < 99)) {
|
2017-03-11 06:31:54 +08:00
|
|
|
change = android::base::StringPrintf(
|
|
|
|
"%s%d.%u%s", prefix, permille / 10,
|
2015-08-25 02:08:00 +08:00
|
|
|
((permille < 0) ? (-permille % 10) : (permille % 10)),
|
|
|
|
units);
|
|
|
|
} else {
|
2017-03-11 06:31:54 +08:00
|
|
|
change = android::base::StringPrintf(
|
|
|
|
"%s%d%s", prefix, (permille + 5) / 10, units);
|
2015-08-25 02:08:00 +08:00
|
|
|
}
|
2017-03-11 06:31:54 +08:00
|
|
|
ssize_t spaces = EntryBaseConstants::pruned_len - 2 -
|
|
|
|
pruned.length() - change.length();
|
2015-08-25 02:08:00 +08:00
|
|
|
if ((spaces <= 0) && pruned.length()) {
|
|
|
|
spaces = 1;
|
|
|
|
}
|
2016-12-20 06:23:03 +08:00
|
|
|
if (spaces > 0) {
|
2015-08-25 02:08:00 +08:00
|
|
|
change += android::base::StringPrintf("%*s", (int)spaces, "");
|
|
|
|
}
|
|
|
|
pruned = change + pruned;
|
|
|
|
}
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2015-08-28 23:02:59 +08:00
|
|
|
std::string output = formatLine(name, size, pruned);
|
|
|
|
|
|
|
|
if (uid != AID_SYSTEM) {
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const size_t maximum_sorted_entries = 32;
|
2017-03-11 06:31:54 +08:00
|
|
|
std::unique_ptr<const PidEntry* []> sorted =
|
|
|
|
stat.pidSystemTable[id].sort(uid, (pid_t)0, maximum_sorted_entries);
|
2015-08-28 23:02:59 +08:00
|
|
|
|
|
|
|
if (!sorted.get()) {
|
|
|
|
return output;
|
|
|
|
}
|
|
|
|
std::string byPid;
|
|
|
|
size_t index;
|
|
|
|
bool hasDropped = false;
|
|
|
|
for (index = 0; index < maximum_sorted_entries; ++index) {
|
2017-03-11 06:31:54 +08:00
|
|
|
const PidEntry* entry = sorted[index];
|
2015-08-28 23:02:59 +08:00
|
|
|
if (!entry) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (entry->getSizes() <= (getSizes() / 100)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (entry->getDropped()) {
|
|
|
|
hasDropped = true;
|
|
|
|
}
|
|
|
|
byPid += entry->format(stat, id);
|
|
|
|
}
|
2017-03-11 06:31:54 +08:00
|
|
|
if (index > 1) { // print this only if interesting
|
2015-08-28 23:02:59 +08:00
|
|
|
std::string ditto("\" ");
|
2017-03-11 06:31:54 +08:00
|
|
|
output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
|
|
|
|
hasDropped ? ditto : std::string(""));
|
2015-08-28 23:02:59 +08:00
|
|
|
output += byPid;
|
|
|
|
}
|
|
|
|
|
|
|
|
return output;
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
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"));
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string PidEntry::format(const LogStatistics& stat,
|
|
|
|
log_id_t /* id */) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
uid_t uid = getUid();
|
2015-12-18 01:58:43 +08:00
|
|
|
pid_t pid = getPid();
|
|
|
|
std::string name = android::base::StringPrintf("%5u/%u", pid, uid);
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* nameTmp = getName();
|
2015-08-22 07:44:30 +08:00
|
|
|
if (nameTmp) {
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
2015-08-22 07:44:30 +08:00
|
|
|
} else if ((nameTmp = stat.uidToName(uid))) {
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
|
|
|
free(const_cast<char*>(nameTmp));
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string size = android::base::StringPrintf("%zu", getSizes());
|
2015-08-22 07:44:30 +08:00
|
|
|
|
|
|
|
std::string pruned = "";
|
|
|
|
size_t dropped = getDropped();
|
|
|
|
if (dropped) {
|
|
|
|
pruned = android::base::StringPrintf("%zu", dropped);
|
|
|
|
}
|
|
|
|
|
|
|
|
return formatLine(name, size, pruned);
|
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
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"),
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string("NUM"));
|
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string TidEntry::format(const LogStatistics& stat,
|
|
|
|
log_id_t /* id */) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
uid_t uid = getUid();
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string name = android::base::StringPrintf("%5u/%u", getTid(), uid);
|
|
|
|
const char* nameTmp = getName();
|
2015-08-22 07:44:30 +08:00
|
|
|
if (nameTmp) {
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
2015-08-22 07:44:30 +08:00
|
|
|
} else if ((nameTmp = stat.uidToName(uid))) {
|
|
|
|
// if we do not have a PID name, lets punt to try UID name?
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", nameTmp);
|
|
|
|
free(const_cast<char*>(nameTmp));
|
2015-08-22 07:44:30 +08:00
|
|
|
// We tried, better to not have a name at all, we still
|
|
|
|
// have TID/UID by number to report in any case.
|
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string size = android::base::StringPrintf("%zu", getSizes());
|
2015-08-22 07:44:30 +08:00
|
|
|
|
|
|
|
std::string pruned = "";
|
|
|
|
size_t dropped = getDropped();
|
|
|
|
if (dropped) {
|
|
|
|
pruned = android::base::StringPrintf("%zu", dropped);
|
|
|
|
}
|
|
|
|
|
|
|
|
return formatLine(name, size, pruned);
|
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
bool isprune = worstUidEnabledForLogid(id);
|
2017-03-11 06:31:54 +08:00
|
|
|
return formatLine(name, std::string("Size"),
|
|
|
|
std::string(isprune ? "Prune" : "")) +
|
|
|
|
formatLine(std::string(" TAG/UID TAGNAME"),
|
|
|
|
std::string("BYTES"), std::string(isprune ? "NUM" : ""));
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string TagEntry::format(const LogStatistics& /* stat */,
|
|
|
|
log_id_t /* id */) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string name;
|
|
|
|
uid_t uid = getUid();
|
|
|
|
if (uid == (uid_t)-1) {
|
2017-03-11 06:31:54 +08:00
|
|
|
name = android::base::StringPrintf("%7u", getKey());
|
2015-03-17 03:04:09 +08:00
|
|
|
} else {
|
2017-03-11 06:31:54 +08:00
|
|
|
name = android::base::StringPrintf("%7u/%u", getKey(), uid);
|
2015-03-17 03:04:09 +08:00
|
|
|
}
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* nameTmp = getName();
|
2015-08-22 07:44:30 +08:00
|
|
|
if (nameTmp) {
|
|
|
|
name += android::base::StringPrintf(
|
2017-03-11 06:31:54 +08:00
|
|
|
"%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
|
2015-08-22 07:44:30 +08:00
|
|
|
}
|
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
std::string size = android::base::StringPrintf("%zu", getSizes());
|
2015-08-22 07:44:30 +08:00
|
|
|
|
|
|
|
std::string pruned = "";
|
2016-07-15 06:34:30 +08:00
|
|
|
size_t dropped = getDropped();
|
|
|
|
if (dropped) {
|
|
|
|
pruned = android::base::StringPrintf("%zu", dropped);
|
|
|
|
}
|
2015-08-22 07:44:30 +08:00
|
|
|
|
|
|
|
return formatLine(name, size, pruned);
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
|
2015-12-18 01:58:43 +08:00
|
|
|
std::string LogStatistics::format(uid_t uid, pid_t pid,
|
|
|
|
unsigned int logMask) const {
|
2014-04-07 22:05:40 +08:00
|
|
|
static const unsigned short spaces_total = 19;
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// Report on total logging, current and for all time
|
|
|
|
|
2015-08-20 06:33:01 +08:00
|
|
|
std::string output = "size/num";
|
2014-02-07 06:48:50 +08:00
|
|
|
size_t oldLength;
|
2015-03-11 04:51:35 +08:00
|
|
|
short spaces = 1;
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
log_id_for_each(id) {
|
2016-10-06 03:34:37 +08:00
|
|
|
if (!(logMask & (1 << id))) continue;
|
2015-03-11 04:51:35 +08:00
|
|
|
oldLength = output.length();
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
2015-08-20 06:33:01 +08:00
|
|
|
output += android::base::StringPrintf("%*s%s", spaces, "",
|
|
|
|
android_log_id_to_name(id));
|
2015-03-11 04:51:35 +08:00
|
|
|
spaces += spaces_total + oldLength - output.length();
|
|
|
|
}
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
|
|
|
output += android::base::StringPrintf("%*sTotal", spaces, "");
|
2014-04-05 07:35:59 +08:00
|
|
|
|
2016-10-06 03:34:37 +08:00
|
|
|
static const char TotalStr[] = "\nTotal";
|
|
|
|
spaces = 10 - strlen(TotalStr);
|
|
|
|
output += TotalStr;
|
2014-04-05 07:35:59 +08:00
|
|
|
|
2016-10-06 03:34:37 +08:00
|
|
|
size_t totalSize = 0;
|
|
|
|
size_t totalEls = 0;
|
2015-03-11 04:51:35 +08:00
|
|
|
log_id_for_each(id) {
|
2016-10-06 03:34:37 +08:00
|
|
|
if (!(logMask & (1 << id))) continue;
|
2015-03-11 04:51:35 +08:00
|
|
|
oldLength = output.length();
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
|
|
|
size_t szs = sizesTotal(id);
|
|
|
|
totalSize += szs;
|
|
|
|
size_t els = elementsTotal(id);
|
|
|
|
totalEls += els;
|
2017-03-11 06:31:54 +08:00
|
|
|
output +=
|
|
|
|
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
2015-03-11 04:51:35 +08:00
|
|
|
spaces += spaces_total + oldLength - output.length();
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
2017-03-11 06:31:54 +08:00
|
|
|
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
|
|
|
|
totalEls);
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2016-10-06 03:34:37 +08:00
|
|
|
static const char NowStr[] = "\nNow";
|
|
|
|
spaces = 10 - strlen(NowStr);
|
|
|
|
output += NowStr;
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2016-10-06 03:34:37 +08:00
|
|
|
totalSize = 0;
|
|
|
|
totalEls = 0;
|
2015-03-11 04:51:35 +08:00
|
|
|
log_id_for_each(id) {
|
2016-10-06 03:34:37 +08:00
|
|
|
if (!(logMask & (1 << id))) continue;
|
|
|
|
|
|
|
|
size_t els = elements(id);
|
|
|
|
if (els) {
|
|
|
|
oldLength = output.length();
|
|
|
|
if (spaces < 0) spaces = 0;
|
|
|
|
size_t szs = sizes(id);
|
|
|
|
totalSize += szs;
|
|
|
|
totalEls += els;
|
2017-03-11 06:31:54 +08:00
|
|
|
output +=
|
|
|
|
android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
|
2016-10-06 03:34:37 +08:00
|
|
|
spaces -= output.length() - oldLength;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
2016-10-06 03:34:37 +08:00
|
|
|
spaces += spaces_total;
|
|
|
|
}
|
|
|
|
if (spaces < 0) spaces = 0;
|
2017-03-11 06:31:54 +08:00
|
|
|
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
|
|
|
|
totalEls);
|
2016-10-06 03:34:37 +08:00
|
|
|
|
|
|
|
static const char OverheadStr[] = "\nOverhead";
|
|
|
|
spaces = 10 - strlen(OverheadStr);
|
|
|
|
output += OverheadStr;
|
|
|
|
|
|
|
|
totalSize = 0;
|
|
|
|
log_id_for_each(id) {
|
|
|
|
if (!(logMask & (1 << id))) continue;
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
size_t els = elements(id);
|
2014-02-07 06:48:50 +08:00
|
|
|
if (els) {
|
2015-03-11 04:51:35 +08:00
|
|
|
oldLength = output.length();
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
|
|
|
// estimate the std::list overhead.
|
|
|
|
static const size_t overhead =
|
|
|
|
((sizeof(LogBufferElement) + sizeof(uint64_t) - 1) &
|
2017-03-11 06:31:54 +08:00
|
|
|
-sizeof(uint64_t)) +
|
2016-10-06 03:34:37 +08:00
|
|
|
sizeof(std::list<LogBufferElement*>);
|
|
|
|
size_t szs = sizes(id) + els * overhead;
|
|
|
|
totalSize += szs;
|
|
|
|
output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
|
2015-03-11 04:51:35 +08:00
|
|
|
spaces -= output.length() - oldLength;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
|
|
|
spaces += spaces_total;
|
|
|
|
}
|
2016-10-07 00:55:21 +08:00
|
|
|
totalSize += sizeOf();
|
2016-10-06 03:34:37 +08:00
|
|
|
if (spaces < 0) spaces = 0;
|
|
|
|
output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
|
2014-02-07 06:48:50 +08:00
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// Report on Chattiest
|
2014-03-27 01:46:39 +08:00
|
|
|
|
2015-08-22 07:44:30 +08:00
|
|
|
std::string name;
|
|
|
|
|
2015-03-11 04:51:35 +08:00
|
|
|
// Chattiest by application (UID)
|
|
|
|
log_id_for_each(id) {
|
2016-10-06 03:34:37 +08:00
|
|
|
if (!(logMask & (1 << id))) continue;
|
2014-03-27 01:46:39 +08:00
|
|
|
|
2017-03-11 06:31:54 +08:00
|
|
|
name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
|
|
|
|
: "Logging for your UID in %s log buffer:";
|
2015-12-18 01:58:43 +08:00
|
|
|
output += uidTable[id].format(*this, uid, pid, name, id);
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
2015-03-11 04:51:35 +08:00
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
if (enable) {
|
2017-03-11 06:31:54 +08:00
|
|
|
name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
|
|
|
|
: "Logging for this PID:";
|
2015-12-18 01:58:43 +08:00
|
|
|
output += pidTable.format(*this, uid, pid, name);
|
|
|
|
name = "Chattiest TIDs";
|
2016-10-06 03:34:37 +08:00
|
|
|
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
|
2015-12-18 01:58:43 +08:00
|
|
|
name += ":";
|
|
|
|
output += tidTable.format(*this, uid, pid, name);
|
2015-04-21 04:35:15 +08:00
|
|
|
}
|
|
|
|
|
2015-04-14 05:24:45 +08:00
|
|
|
if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
|
2015-12-18 01:58:43 +08:00
|
|
|
name = "Chattiest events log buffer TAGs";
|
2016-10-06 03:34:37 +08:00
|
|
|
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
|
2015-12-18 01:58:43 +08:00
|
|
|
name += ":";
|
|
|
|
output += tagTable.format(*this, uid, pid, name, LOG_ID_EVENTS);
|
2015-04-14 05:24:45 +08:00
|
|
|
}
|
|
|
|
|
2015-12-05 02:59:45 +08:00
|
|
|
if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
|
2015-12-18 01:58:43 +08:00
|
|
|
name = "Chattiest security log buffer TAGs";
|
2016-10-06 03:34:37 +08:00
|
|
|
if (pid) name += android::base::StringPrintf(" for PID %d", pid);
|
2015-12-18 01:58:43 +08:00
|
|
|
name += ":";
|
2017-03-11 06:31:54 +08:00
|
|
|
output +=
|
|
|
|
securityTagTable.format(*this, uid, pid, name, LOG_ID_SECURITY);
|
2015-12-05 02:59:45 +08:00
|
|
|
}
|
|
|
|
|
2015-08-21 01:01:44 +08:00
|
|
|
return output;
|
2014-02-07 06:48:50 +08:00
|
|
|
}
|
2014-04-07 22:15:33 +08:00
|
|
|
|
2015-03-16 23:26:05 +08:00
|
|
|
namespace android {
|
|
|
|
|
|
|
|
uid_t pidToUid(pid_t pid) {
|
2015-03-11 04:51:35 +08:00
|
|
|
char buffer[512];
|
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
|
2017-03-11 06:31:54 +08:00
|
|
|
FILE* fp = fopen(buffer, "r");
|
2015-03-11 04:51:35 +08:00
|
|
|
if (fp) {
|
|
|
|
while (fgets(buffer, sizeof(buffer), fp)) {
|
|
|
|
int uid;
|
2015-04-15 04:07:29 +08:00
|
|
|
if (sscanf(buffer, "Uid: %d", &uid) == 1) {
|
2015-03-11 04:51:35 +08:00
|
|
|
fclose(fp);
|
|
|
|
return uid;
|
2014-04-07 22:15:33 +08:00
|
|
|
}
|
|
|
|
}
|
2015-03-11 04:51:35 +08:00
|
|
|
fclose(fp);
|
2014-04-07 22:15:33 +08:00
|
|
|
}
|
2017-03-11 06:31:54 +08:00
|
|
|
return AID_LOGD; // associate this with the logger
|
2014-04-07 22:15:33 +08:00
|
|
|
}
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uid_t LogStatistics::pidToUid(pid_t pid) {
|
2015-05-20 00:12:30 +08:00
|
|
|
return pidTable.add(pid)->second.getUid();
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// caller must free character string
|
2017-03-11 06:31:54 +08:00
|
|
|
const char* LogStatistics::pidToName(pid_t pid) const {
|
2015-08-22 07:44:30 +08:00
|
|
|
// An inconvenient truth ... getName() can alter the object
|
2017-03-11 06:31:54 +08:00
|
|
|
pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
|
|
|
|
const char* name = writablePidTable.add(pid)->second.getName();
|
2015-04-14 05:24:45 +08:00
|
|
|
if (!name) {
|
|
|
|
return NULL;
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|
2015-04-14 05:24:45 +08:00
|
|
|
return strdup(name);
|
2015-03-16 23:26:05 +08:00
|
|
|
}
|