Merge changes I1572338c,I39965007,I521753b1
* changes: logd: liblog: logcat: Add LogWhiteBlackList logd: prune by worst offending UID logd: liblog: logcat: Add Statistics
This commit is contained in:
commit
f3dcda5f85
15 changed files with 1776 additions and 44 deletions
|
|
@ -140,12 +140,24 @@ struct logger;
|
||||||
log_id_t android_logger_get_id(struct logger *logger);
|
log_id_t android_logger_get_id(struct logger *logger);
|
||||||
|
|
||||||
int android_logger_clear(struct logger *logger);
|
int android_logger_clear(struct logger *logger);
|
||||||
int android_logger_get_log_size(struct logger *logger);
|
long android_logger_get_log_size(struct logger *logger);
|
||||||
int android_logger_get_log_readable_size(struct logger *logger);
|
#ifdef USERDEBUG_BUILD
|
||||||
|
int android_logger_set_log_size(struct logger *logger, unsigned long size);
|
||||||
|
#endif
|
||||||
|
long android_logger_get_log_readable_size(struct logger *logger);
|
||||||
int android_logger_get_log_version(struct logger *logger);
|
int android_logger_get_log_version(struct logger *logger);
|
||||||
|
|
||||||
struct logger_list;
|
struct logger_list;
|
||||||
|
|
||||||
|
ssize_t android_logger_get_statistics(struct logger_list *logger_list,
|
||||||
|
char *buf, size_t len);
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
ssize_t android_logger_get_prune_list(struct logger_list *logger_list,
|
||||||
|
char *buf, size_t len);
|
||||||
|
int android_logger_set_prune_list(struct logger_list *logger_list,
|
||||||
|
char *buf, size_t len);
|
||||||
|
#endif
|
||||||
|
|
||||||
struct logger_list *android_logger_list_alloc(int mode,
|
struct logger_list *android_logger_list_alloc(int mode,
|
||||||
unsigned int tail,
|
unsigned int tail,
|
||||||
pid_t pid);
|
pid_t pid);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ else
|
||||||
liblog_sources := logd_write_kern.c
|
liblog_sources := logd_write_kern.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
|
||||||
|
liblog_cflags := -DUSERDEBUG_BUILD=1
|
||||||
|
endif
|
||||||
|
|
||||||
# some files must not be compiled when building against Mingw
|
# some files must not be compiled when building against Mingw
|
||||||
# they correspond to features not used by our host development tools
|
# they correspond to features not used by our host development tools
|
||||||
# which are also hard or even impossible to port to native Win32
|
# which are also hard or even impossible to port to native Win32
|
||||||
|
|
@ -80,11 +84,13 @@ include $(BUILD_HOST_STATIC_LIBRARY)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := liblog
|
LOCAL_MODULE := liblog
|
||||||
LOCAL_SRC_FILES := $(liblog_target_sources)
|
LOCAL_SRC_FILES := $(liblog_target_sources)
|
||||||
|
LOCAL_CFLAGS := $(liblog_cflags)
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := liblog
|
LOCAL_MODULE := liblog
|
||||||
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
|
LOCAL_WHOLE_STATIC_LIBRARIES := liblog
|
||||||
|
LOCAL_CFLAGS := $(liblog_cflags)
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
||||||
include $(call first-makefiles-under,$(LOCAL_PATH))
|
include $(call first-makefiles-under,$(LOCAL_PATH))
|
||||||
|
|
|
||||||
|
|
@ -296,11 +296,8 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int android_logger_clear(struct logger *logger)
|
static int check_log_success(char *buf, ssize_t ret)
|
||||||
{
|
{
|
||||||
char buf[512];
|
|
||||||
|
|
||||||
ssize_t ret = send_log_msg(logger, "clear %d", buf, sizeof(buf));
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -312,8 +309,16 @@ int android_logger_clear(struct logger *logger)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int android_logger_clear(struct logger *logger)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
return check_log_success(buf,
|
||||||
|
send_log_msg(logger, "clear %d", buf, sizeof(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
/* returns the total size of the log's ring buffer */
|
/* returns the total size of the log's ring buffer */
|
||||||
int android_logger_get_log_size(struct logger *logger)
|
long android_logger_get_log_size(struct logger *logger)
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
|
|
@ -326,14 +331,28 @@ int android_logger_get_log_size(struct logger *logger)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return atoi(buf);
|
return atol(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
int android_logger_set_log_size(struct logger *logger, unsigned long size)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "setLogSize %d %lu",
|
||||||
|
logger ? logger->id : (unsigned) -1, size);
|
||||||
|
|
||||||
|
return check_log_success(buf, send_log_msg(NULL, NULL, buf, sizeof(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USERDEBUG_BUILD */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns the readable size of the log's ring buffer (that is, amount of the
|
* returns the readable size of the log's ring buffer (that is, amount of the
|
||||||
* log consumed)
|
* log consumed)
|
||||||
*/
|
*/
|
||||||
int android_logger_get_log_readable_size(struct logger *logger)
|
long android_logger_get_log_readable_size(struct logger *logger)
|
||||||
{
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
|
|
@ -346,7 +365,7 @@ int android_logger_get_log_readable_size(struct logger *logger)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return atoi(buf);
|
return atol(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -357,6 +376,58 @@ int android_logger_get_log_version(struct logger *logger UNUSED)
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns statistics
|
||||||
|
*/
|
||||||
|
ssize_t android_logger_get_statistics(struct logger_list *logger_list,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
struct listnode *node;
|
||||||
|
struct logger *logger;
|
||||||
|
char *cp = buf;
|
||||||
|
size_t remaining = len;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
n = snprintf(cp, remaining, "getStatistics");
|
||||||
|
n = min(n, remaining);
|
||||||
|
remaining -= n;
|
||||||
|
cp += n;
|
||||||
|
|
||||||
|
logger_for_each(logger, logger_list) {
|
||||||
|
n = snprintf(cp, remaining, " %d", logger->id);
|
||||||
|
n = min(n, remaining);
|
||||||
|
remaining -= n;
|
||||||
|
cp += n;
|
||||||
|
}
|
||||||
|
return send_log_msg(NULL, NULL, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
return send_log_msg(NULL, "getPruneList", buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
const char cmd[] = "setPruneList ";
|
||||||
|
const size_t cmdlen = sizeof(cmd) - 1;
|
||||||
|
|
||||||
|
if (strlen(buf) > (len - cmdlen)) {
|
||||||
|
return -ENOMEM; /* KISS */
|
||||||
|
}
|
||||||
|
memmove(buf + cmdlen, buf, len - cmdlen);
|
||||||
|
buf[len - 1] = '\0';
|
||||||
|
memcpy(buf, cmd, cmdlen);
|
||||||
|
|
||||||
|
return check_log_success(buf, send_log_msg(NULL, NULL, buf, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USERDEBUG_BUILD */
|
||||||
|
|
||||||
struct logger_list *android_logger_list_alloc(int mode,
|
struct logger_list *android_logger_list_alloc(int mode,
|
||||||
unsigned int tail,
|
unsigned int tail,
|
||||||
pid_t pid)
|
pid_t pid)
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,8 @@ typedef char bool;
|
||||||
logger != node_to_item(&(logger_list)->node, struct logger, node); \
|
logger != node_to_item(&(logger_list)->node, struct logger, node); \
|
||||||
logger = node_to_item((logger)->node.next, struct logger, node))
|
logger = node_to_item((logger)->node.next, struct logger, node))
|
||||||
|
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
|
||||||
/* In the future, we would like to make this list extensible */
|
/* In the future, we would like to make this list extensible */
|
||||||
static const char *LOG_NAME[LOG_ID_MAX] = {
|
static const char *LOG_NAME[LOG_ID_MAX] = {
|
||||||
[LOG_ID_MAIN] = "main",
|
[LOG_ID_MAIN] = "main",
|
||||||
|
|
@ -225,16 +227,26 @@ int android_logger_clear(struct logger *logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* returns the total size of the log's ring buffer */
|
/* returns the total size of the log's ring buffer */
|
||||||
int android_logger_get_log_size(struct logger *logger)
|
long android_logger_get_log_size(struct logger *logger)
|
||||||
{
|
{
|
||||||
return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
|
return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
int android_logger_set_log_size(struct logger *logger UNUSED,
|
||||||
|
unsigned long size UNUSED)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USERDEBUG_BUILD */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* returns the readable size of the log's ring buffer (that is, amount of the
|
* returns the readable size of the log's ring buffer (that is, amount of the
|
||||||
* log consumed)
|
* log consumed)
|
||||||
*/
|
*/
|
||||||
int android_logger_get_log_readable_size(struct logger *logger)
|
long android_logger_get_log_readable_size(struct logger *logger)
|
||||||
{
|
{
|
||||||
return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
|
return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
|
||||||
}
|
}
|
||||||
|
|
@ -248,6 +260,37 @@ int android_logger_get_log_version(struct logger *logger)
|
||||||
return (ret < 0) ? 1 : ret;
|
return (ret < 0) ? 1 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* returns statistics
|
||||||
|
*/
|
||||||
|
static const char unsupported[] = "18\nNot Supported\n\f";
|
||||||
|
|
||||||
|
ssize_t android_logger_get_statistics(struct logger_list *logger_list UNUSED,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
strncpy(buf, unsupported, len);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
ssize_t android_logger_get_prune_list(struct logger_list *logger_list UNUSED,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
strncpy(buf, unsupported, len);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_logger_set_prune_list(struct logger_list *logger_list UNUSED,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
static const char unsupported_error[] = "Unsupported";
|
||||||
|
strncpy(buf, unsupported, len);
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USERDEBUG_BUILD */
|
||||||
|
|
||||||
struct logger_list *android_logger_list_alloc(int mode,
|
struct logger_list *android_logger_list_alloc(int mode,
|
||||||
unsigned int tail,
|
unsigned int tail,
|
||||||
pid_t pid)
|
pid_t pid)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@
|
||||||
LOCAL_PATH:= $(call my-dir)
|
LOCAL_PATH:= $(call my-dir)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
|
||||||
|
LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
|
||||||
|
endif
|
||||||
|
|
||||||
LOCAL_SRC_FILES:= logcat.cpp event.logtags
|
LOCAL_SRC_FILES:= logcat.cpp event.logtags
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := liblog
|
LOCAL_SHARED_LIBRARIES := liblog
|
||||||
|
|
|
||||||
|
|
@ -225,11 +225,23 @@ static void show_help(const char *cmd)
|
||||||
" -t <count> print only the most recent <count> lines (implies -d)\n"
|
" -t <count> print only the most recent <count> lines (implies -d)\n"
|
||||||
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
|
" -T <count> print only the most recent <count> lines (does not imply -d)\n"
|
||||||
" -g get the size of the log's ring buffer and exit\n"
|
" -g get the size of the log's ring buffer and exit\n"
|
||||||
" -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio'\n"
|
" -b <buffer> Request alternate ring buffer, 'main', 'system', 'radio',\n"
|
||||||
" or 'events'. Multiple -b parameters are allowed and the\n"
|
" 'events' or 'all'. Multiple -b parameters are allowed and\n"
|
||||||
" results are interleaved. The default is -b main -b system.\n"
|
" results are interleaved. The default is -b main -b system.\n"
|
||||||
" -B output the log in binary");
|
" -B output the log in binary.\n"
|
||||||
|
" -S output statistics.\n");
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
fprintf(stderr, "--------------------- eng & userdebug builds only ---------------------------\n"
|
||||||
|
" -G <count> set size of log's ring buffer and exit\n"
|
||||||
|
" -p output prune white and ~black list\n"
|
||||||
|
" -P '<list> ...' set prune white and ~black list; UID, /PID or !(worst UID)\n"
|
||||||
|
" default is ~!, prune worst UID.\n"
|
||||||
|
"-----------------------------------------------------------------------------\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
fprintf(stderr,"\nfilterspecs are a series of \n"
|
fprintf(stderr,"\nfilterspecs are a series of \n"
|
||||||
" <tag>[:priority]\n\n"
|
" <tag>[:priority]\n\n"
|
||||||
|
|
@ -278,6 +290,12 @@ int main(int argc, char **argv)
|
||||||
int hasSetLogFormat = 0;
|
int hasSetLogFormat = 0;
|
||||||
int clearLog = 0;
|
int clearLog = 0;
|
||||||
int getLogSize = 0;
|
int getLogSize = 0;
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
unsigned long setLogSize = 0;
|
||||||
|
int getPruneList = 0;
|
||||||
|
char *setPruneList = NULL;
|
||||||
|
#endif
|
||||||
|
int printStatistics = 0;
|
||||||
int mode = O_RDONLY;
|
int mode = O_RDONLY;
|
||||||
const char *forceFilters = NULL;
|
const char *forceFilters = NULL;
|
||||||
log_device_t* devices = NULL;
|
log_device_t* devices = NULL;
|
||||||
|
|
@ -303,7 +321,13 @@ int main(int argc, char **argv)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = getopt(argc, argv, "cdt:T:gsQf:r::n:v:b:B");
|
ret = getopt(argc, argv,
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
"cdt:T:gG:sQf:r::n:v:b:BSpP:"
|
||||||
|
#else
|
||||||
|
"cdt:T:gsQf:r::n:v:b:BS"
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
|
|
@ -335,7 +359,89 @@ int main(int argc, char **argv)
|
||||||
getLogSize = 1;
|
getLogSize = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
case 'G': {
|
||||||
|
// would use atol if not for the multiplier
|
||||||
|
char *cp = optarg;
|
||||||
|
setLogSize = 0;
|
||||||
|
while (('0' <= *cp) && (*cp <= '9')) {
|
||||||
|
setLogSize *= 10;
|
||||||
|
setLogSize += *cp - '0';
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(*cp) {
|
||||||
|
case 'g':
|
||||||
|
case 'G':
|
||||||
|
setLogSize *= 1024;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 'm':
|
||||||
|
case 'M':
|
||||||
|
setLogSize *= 1024;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case 'k':
|
||||||
|
case 'K':
|
||||||
|
setLogSize *= 1024;
|
||||||
|
/* FALLTHRU */
|
||||||
|
case '\0':
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
setLogSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setLogSize) {
|
||||||
|
fprintf(stderr, "ERROR: -G <num><multiplier>\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
getPruneList = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
setPruneList = optarg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
case 'b': {
|
case 'b': {
|
||||||
|
if (strcmp(optarg, "all") == 0) {
|
||||||
|
while (devices) {
|
||||||
|
dev = devices;
|
||||||
|
devices = dev->next;
|
||||||
|
delete dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = devices = new log_device_t("main", false, 'm');
|
||||||
|
android::g_devCount = 1;
|
||||||
|
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
|
||||||
|
dev->next = new log_device_t("system", false, 's');
|
||||||
|
if (dev->next) {
|
||||||
|
dev = dev->next;
|
||||||
|
android::g_devCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (android_name_to_log_id("radio") == LOG_ID_RADIO) {
|
||||||
|
dev->next = new log_device_t("radio", false, 'r');
|
||||||
|
if (dev->next) {
|
||||||
|
dev = dev->next;
|
||||||
|
android::g_devCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (android_name_to_log_id("events") == LOG_ID_EVENTS) {
|
||||||
|
dev->next = new log_device_t("events", true, 'e');
|
||||||
|
if (dev->next) {
|
||||||
|
android::g_devCount++;
|
||||||
|
needBinary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bool binary = strcmp(optarg, "events") == 0;
|
bool binary = strcmp(optarg, "events") == 0;
|
||||||
if (binary) {
|
if (binary) {
|
||||||
needBinary = true;
|
needBinary = true;
|
||||||
|
|
@ -470,6 +576,10 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'S':
|
||||||
|
printStatistics = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr,"Unrecognized Option\n");
|
fprintf(stderr,"Unrecognized Option\n");
|
||||||
android::show_help(argv[0]);
|
android::show_help(argv[0]);
|
||||||
|
|
@ -563,8 +673,17 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
if (setLogSize && android_logger_set_log_size(dev->logger, setLogSize)) {
|
||||||
|
perror("setLogSize");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
if (getLogSize) {
|
if (getLogSize) {
|
||||||
int size, readable;
|
long size, readable;
|
||||||
|
|
||||||
size = android_logger_get_log_size(dev->logger);
|
size = android_logger_get_log_size(dev->logger);
|
||||||
if (size < 0) {
|
if (size < 0) {
|
||||||
|
|
@ -578,7 +697,7 @@ int main(int argc, char **argv)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: ring buffer is %dKb (%dKb consumed), "
|
printf("%s: ring buffer is %ldKb (%ldKb consumed), "
|
||||||
"max entry is %db, max payload is %db\n", dev->device,
|
"max entry is %db, max payload is %db\n", dev->device,
|
||||||
size / 1024, readable / 1024,
|
size / 1024, readable / 1024,
|
||||||
(int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
|
(int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
|
||||||
|
|
@ -587,9 +706,95 @@ int main(int argc, char **argv)
|
||||||
dev = dev->next;
|
dev = dev->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
if (setPruneList) {
|
||||||
|
size_t len = strlen(setPruneList) + 32; // margin to allow rc
|
||||||
|
char *buf = (char *) malloc(len);
|
||||||
|
|
||||||
|
strcpy(buf, setPruneList);
|
||||||
|
int ret = android_logger_set_prune_list(logger_list, buf, len);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
perror("setPruneList");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
printStatistics || getPruneList
|
||||||
|
#else
|
||||||
|
printStatistics
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
size_t len = 8192;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
for(int retry = 32;
|
||||||
|
(retry >= 0) && ((buf = new char [len]));
|
||||||
|
delete [] buf, --retry) {
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
if (getPruneList) {
|
||||||
|
android_logger_get_prune_list(logger_list, buf, len);
|
||||||
|
} else {
|
||||||
|
android_logger_get_statistics(logger_list, buf, len);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
android_logger_get_statistics(logger_list, buf, len);
|
||||||
|
#endif
|
||||||
|
buf[len-1] = '\0';
|
||||||
|
size_t ret = atol(buf) + 1;
|
||||||
|
if (ret < 4) {
|
||||||
|
delete [] buf;
|
||||||
|
buf = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool check = ret <= len;
|
||||||
|
len = ret;
|
||||||
|
if (check) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buf) {
|
||||||
|
perror("response read");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove trailing FF
|
||||||
|
char *cp = buf + len - 1;
|
||||||
|
*cp = '\0';
|
||||||
|
bool truncated = *--cp != '\f';
|
||||||
|
if (!truncated) {
|
||||||
|
*cp = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// squash out the byte count
|
||||||
|
cp = buf;
|
||||||
|
if (!truncated) {
|
||||||
|
while (isdigit(*cp) || (*cp == '\n')) {
|
||||||
|
++cp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s", cp);
|
||||||
|
delete [] buf;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (getLogSize) {
|
if (getLogSize) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
if (setLogSize || setPruneList) {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (clearLog) {
|
if (clearLog) {
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@ include $(CLEAR_VARS)
|
||||||
|
|
||||||
LOCAL_MODULE:= logd
|
LOCAL_MODULE:= logd
|
||||||
|
|
||||||
|
ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
|
||||||
|
LOCAL_CFLAGS += -DUSERDEBUG_BUILD=1
|
||||||
|
endif
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
LogCommand.cpp \
|
LogCommand.cpp \
|
||||||
|
|
@ -13,12 +17,15 @@ LOCAL_SRC_FILES := \
|
||||||
FlushCommand.cpp \
|
FlushCommand.cpp \
|
||||||
LogBuffer.cpp \
|
LogBuffer.cpp \
|
||||||
LogBufferElement.cpp \
|
LogBufferElement.cpp \
|
||||||
LogTimes.cpp
|
LogTimes.cpp \
|
||||||
|
LogStatistics.cpp \
|
||||||
|
LogWhiteBlackList.cpp
|
||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := \
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
libsysutils \
|
libsysutils \
|
||||||
liblog \
|
liblog \
|
||||||
libcutils
|
libcutils \
|
||||||
|
libutils
|
||||||
|
|
||||||
LOCAL_MODULE_TAGS := optional
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,15 @@ CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
|
||||||
// registerCmd(new ShutdownCmd(buf, writer, swl));
|
// registerCmd(new ShutdownCmd(buf, writer, swl));
|
||||||
registerCmd(new ClearCmd(buf));
|
registerCmd(new ClearCmd(buf));
|
||||||
registerCmd(new GetBufSizeCmd(buf));
|
registerCmd(new GetBufSizeCmd(buf));
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
registerCmd(new SetBufSizeCmd(buf));
|
||||||
|
#endif
|
||||||
registerCmd(new GetBufSizeUsedCmd(buf));
|
registerCmd(new GetBufSizeUsedCmd(buf));
|
||||||
|
registerCmd(new GetStatisticsCmd(buf));
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
registerCmd(new SetPruneListCmd(buf));
|
||||||
|
registerCmd(new GetPruneListCmd(buf));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
|
CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
|
||||||
|
|
@ -109,6 +117,43 @@ int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
|
||||||
|
: LogCommand("setLogSize")
|
||||||
|
, mBuf(*buf)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
|
||||||
|
int argc, char **argv) {
|
||||||
|
if (!clientHasLogCredentials(cli)) {
|
||||||
|
cli->sendMsg("Permission Denied");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 3) {
|
||||||
|
cli->sendMsg("Missing Argument");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int id = atoi(argv[1]);
|
||||||
|
if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
|
||||||
|
cli->sendMsg("Range Error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long size = atol(argv[2]);
|
||||||
|
if (mBuf.setSize((log_id_t) id, size)) {
|
||||||
|
cli->sendMsg("Range Error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli->sendMsg("success");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USERDEBUG_BUILD
|
||||||
|
|
||||||
CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
|
CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
|
||||||
: LogCommand("getLogSizeUsed")
|
: LogCommand("getLogSizeUsed")
|
||||||
, mBuf(*buf)
|
, mBuf(*buf)
|
||||||
|
|
@ -133,3 +178,120 @@ int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
|
||||||
cli->sendMsg(buf);
|
cli->sendMsg(buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
|
||||||
|
: LogCommand("getStatistics")
|
||||||
|
, mBuf(*buf)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
static void package_string(char **strp) {
|
||||||
|
const char *a = *strp;
|
||||||
|
if (!a) {
|
||||||
|
a = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate total buffer size prefix, count is the string length w/o nul
|
||||||
|
char fmt[32];
|
||||||
|
for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
|
||||||
|
snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *b = *strp;
|
||||||
|
*strp = NULL;
|
||||||
|
asprintf(strp, fmt, a);
|
||||||
|
free(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
|
||||||
|
int argc, char **argv) {
|
||||||
|
uid_t uid = cli->getUid();
|
||||||
|
gid_t gid = cli->getGid();
|
||||||
|
if (clientHasLogCredentials(cli)) {
|
||||||
|
uid = AID_ROOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int logMask = -1;
|
||||||
|
if (argc > 1) {
|
||||||
|
logMask = 0;
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
int id = atoi(argv[i]);
|
||||||
|
if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
|
||||||
|
cli->sendMsg("Range Error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
logMask |= 1 << id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
mBuf.formatStatistics(&buf, uid, logMask);
|
||||||
|
if (!buf) {
|
||||||
|
cli->sendMsg("Failed");
|
||||||
|
} else {
|
||||||
|
package_string(&buf);
|
||||||
|
cli->sendMsg(buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
|
||||||
|
: LogCommand("getPruneList")
|
||||||
|
, mBuf(*buf)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
|
||||||
|
int /*argc*/, char ** /*argv*/) {
|
||||||
|
char *buf = NULL;
|
||||||
|
mBuf.formatPrune(&buf);
|
||||||
|
if (!buf) {
|
||||||
|
cli->sendMsg("Failed");
|
||||||
|
} else {
|
||||||
|
package_string(&buf);
|
||||||
|
cli->sendMsg(buf);
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
|
||||||
|
: LogCommand("setPruneList")
|
||||||
|
, mBuf(*buf)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
|
||||||
|
int argc, char **argv) {
|
||||||
|
if (!clientHasLogCredentials(cli)) {
|
||||||
|
cli->sendMsg("Permission Denied");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *cp = NULL;
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
char *p = cp;
|
||||||
|
if (p) {
|
||||||
|
cp = NULL;
|
||||||
|
asprintf(&cp, "%s %s", p, argv[i]);
|
||||||
|
free(p);
|
||||||
|
} else {
|
||||||
|
asprintf(&cp, "%s", argv[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = mBuf.initPrune(cp);
|
||||||
|
free(cp);
|
||||||
|
|
||||||
|
if (ret) {
|
||||||
|
cli->sendMsg("Invalid");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli->sendMsg("success");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USERDEBUG_BUILD
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,15 @@ private:
|
||||||
|
|
||||||
LogBufferCmd(Clear)
|
LogBufferCmd(Clear)
|
||||||
LogBufferCmd(GetBufSize)
|
LogBufferCmd(GetBufSize)
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
LogBufferCmd(SetBufSize)
|
||||||
|
#endif
|
||||||
LogBufferCmd(GetBufSizeUsed)
|
LogBufferCmd(GetBufSizeUsed)
|
||||||
|
LogBufferCmd(GetStatistics)
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
LogBufferCmd(GetPruneList)
|
||||||
|
LogBufferCmd(SetPruneList)
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,26 @@
|
||||||
#include <log/logger.h>
|
#include <log/logger.h>
|
||||||
|
|
||||||
#include "LogBuffer.h"
|
#include "LogBuffer.h"
|
||||||
|
#include "LogStatistics.h"
|
||||||
|
#include "LogWhiteBlackList.h"
|
||||||
#include "LogReader.h"
|
#include "LogReader.h"
|
||||||
|
|
||||||
|
// Default
|
||||||
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
|
#define LOG_BUFFER_SIZE (256 * 1024) // Tuned on a per-platform basis here?
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
#define log_buffer_size(id) mMaxSize[id]
|
||||||
|
#else
|
||||||
|
#define log_buffer_size(id) LOG_BUFFER_SIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
LogBuffer::LogBuffer(LastLogTimes *times)
|
LogBuffer::LogBuffer(LastLogTimes *times)
|
||||||
: mTimes(*times) {
|
: mTimes(*times) {
|
||||||
int i;
|
|
||||||
for (i = 0; i < LOG_ID_MAX; i++) {
|
|
||||||
mSizes[i] = 0;
|
|
||||||
mElements[i] = 0;
|
|
||||||
}
|
|
||||||
pthread_mutex_init(&mLogElementsLock, NULL);
|
pthread_mutex_init(&mLogElementsLock, NULL);
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
log_id_for_each(i) {
|
||||||
|
mMaxSize[i] = LOG_BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBuffer::log(log_id_t log_id, log_time realtime,
|
void LogBuffer::log(log_id_t log_id, log_time realtime,
|
||||||
|
|
@ -93,8 +101,7 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
|
||||||
LogTimeEntry::unlock();
|
LogTimeEntry::unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
mSizes[log_id] += len;
|
stats.add(len, log_id, uid, pid);
|
||||||
mElements[log_id]++;
|
|
||||||
maybePrune(log_id);
|
maybePrune(log_id);
|
||||||
pthread_mutex_unlock(&mLogElementsLock);
|
pthread_mutex_unlock(&mLogElementsLock);
|
||||||
}
|
}
|
||||||
|
|
@ -104,10 +111,10 @@ void LogBuffer::log(log_id_t log_id, log_time realtime,
|
||||||
//
|
//
|
||||||
// mLogElementsLock must be held when this function is called.
|
// mLogElementsLock must be held when this function is called.
|
||||||
void LogBuffer::maybePrune(log_id_t id) {
|
void LogBuffer::maybePrune(log_id_t id) {
|
||||||
unsigned long sizes = mSizes[id];
|
size_t sizes = stats.sizes(id);
|
||||||
if (sizes > LOG_BUFFER_SIZE) {
|
if (sizes > log_buffer_size(id)) {
|
||||||
unsigned long sizeOver90Percent = sizes - ((LOG_BUFFER_SIZE * 9) / 10);
|
size_t sizeOver90Percent = sizes - ((log_buffer_size(id) * 9) / 10);
|
||||||
unsigned long elements = mElements[id];
|
size_t elements = stats.elements(id);
|
||||||
unsigned long pruneRows = elements * sizeOver90Percent / sizes;
|
unsigned long pruneRows = elements * sizeOver90Percent / sizes;
|
||||||
elements /= 10;
|
elements /= 10;
|
||||||
if (pruneRows <= elements) {
|
if (pruneRows <= elements) {
|
||||||
|
|
@ -136,22 +143,117 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogBufferElementCollection::iterator it = mLogElements.begin();
|
LogBufferElementCollection::iterator it;
|
||||||
|
|
||||||
|
// prune by worst offender by uid
|
||||||
|
while (pruneRows > 0) {
|
||||||
|
// recalculate the worst offender on every batched pass
|
||||||
|
uid_t worst = (uid_t) -1;
|
||||||
|
size_t worst_sizes = 0;
|
||||||
|
size_t second_worst_sizes = 0;
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
if (mPrune.worstUidEnabled())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
LidStatistics &l = stats.id(id);
|
||||||
|
UidStatisticsCollection::iterator iu;
|
||||||
|
for (iu = l.begin(); iu != l.end(); ++iu) {
|
||||||
|
UidStatistics *u = (*iu);
|
||||||
|
size_t sizes = u->sizes();
|
||||||
|
if (worst_sizes < sizes) {
|
||||||
|
second_worst_sizes = worst_sizes;
|
||||||
|
worst_sizes = sizes;
|
||||||
|
worst = u->getUid();
|
||||||
|
}
|
||||||
|
if ((second_worst_sizes < sizes) && (sizes < worst_sizes)) {
|
||||||
|
second_worst_sizes = sizes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kick = false;
|
||||||
|
for(it = mLogElements.begin(); it != mLogElements.end();) {
|
||||||
|
LogBufferElement *e = *it;
|
||||||
|
|
||||||
|
if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e->getLogId() != id) {
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid_t uid = e->getUid();
|
||||||
|
|
||||||
|
if (uid == worst) {
|
||||||
|
it = mLogElements.erase(it);
|
||||||
|
unsigned short len = e->getMsgLen();
|
||||||
|
stats.subtract(len, id, worst, e->getPid());
|
||||||
|
delete e;
|
||||||
|
kick = true;
|
||||||
|
pruneRows--;
|
||||||
|
if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
worst_sizes -= len;
|
||||||
|
}
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
else if (mPrune.naughty(e)) { // BlackListed
|
||||||
|
it = mLogElements.erase(it);
|
||||||
|
stats.subtract(e->getMsgLen(), id, uid, e->getPid());
|
||||||
|
delete e;
|
||||||
|
pruneRows--;
|
||||||
|
if (pruneRows == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!kick
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|| !mPrune.worstUidEnabled()
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
break; // the following loop will ask bad clients to skip/drop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
bool whitelist = false;
|
||||||
|
#endif
|
||||||
|
it = mLogElements.begin();
|
||||||
while((pruneRows > 0) && (it != mLogElements.end())) {
|
while((pruneRows > 0) && (it != mLogElements.end())) {
|
||||||
LogBufferElement *e = *it;
|
LogBufferElement *e = *it;
|
||||||
if (e->getLogId() == id) {
|
if (e->getLogId() == id) {
|
||||||
if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
|
if (oldest && (oldest->mStart <= e->getMonotonicTime())) {
|
||||||
if (mSizes[id] > (2 * LOG_BUFFER_SIZE)) {
|
#ifdef USERDEBUG_BUILD
|
||||||
// kick a misbehaving log reader client off the island
|
if (!whitelist)
|
||||||
oldest->release_Locked();
|
#endif
|
||||||
} else {
|
{
|
||||||
oldest->triggerSkip_Locked(pruneRows);
|
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(pruneRows);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
if (mPrune.nice(e)) { // WhiteListed
|
||||||
|
whitelist = true;
|
||||||
|
it++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
it = mLogElements.erase(it);
|
it = mLogElements.erase(it);
|
||||||
mSizes[id] -= e->getMsgLen();
|
stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
|
||||||
mElements[id]--;
|
|
||||||
delete e;
|
delete e;
|
||||||
pruneRows--;
|
pruneRows--;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -159,6 +261,32 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
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->getMonotonicTime())) {
|
||||||
|
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(pruneRows);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
it = mLogElements.erase(it);
|
||||||
|
stats.subtract(e->getMsgLen(), id, e->getUid(), e->getPid());
|
||||||
|
delete e;
|
||||||
|
pruneRows--;
|
||||||
|
} else {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
LogTimeEntry::unlock();
|
LogTimeEntry::unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,16 +300,42 @@ void LogBuffer::clear(log_id_t id) {
|
||||||
// get the used space associated with "id".
|
// get the used space associated with "id".
|
||||||
unsigned long LogBuffer::getSizeUsed(log_id_t id) {
|
unsigned long LogBuffer::getSizeUsed(log_id_t id) {
|
||||||
pthread_mutex_lock(&mLogElementsLock);
|
pthread_mutex_lock(&mLogElementsLock);
|
||||||
unsigned long retval = mSizes[id];
|
size_t retval = stats.sizes(id);
|
||||||
pthread_mutex_unlock(&mLogElementsLock);
|
pthread_mutex_unlock(&mLogElementsLock);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
// set the total space allocated to "id"
|
||||||
|
int LogBuffer::setSize(log_id_t id, unsigned long size) {
|
||||||
|
// Reasonable limits ...
|
||||||
|
if ((size < (64 * 1024)) || ((256 * 1024 * 1024) < size)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&mLogElementsLock);
|
||||||
|
log_buffer_size(id) = size;
|
||||||
|
pthread_mutex_unlock(&mLogElementsLock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the total space allocated to "id"
|
||||||
|
unsigned long LogBuffer::getSize(log_id_t id) {
|
||||||
|
pthread_mutex_lock(&mLogElementsLock);
|
||||||
|
size_t retval = log_buffer_size(id);
|
||||||
|
pthread_mutex_unlock(&mLogElementsLock);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // ! USERDEBUG_BUILD
|
||||||
|
|
||||||
// get the total space allocated to "id"
|
// get the total space allocated to "id"
|
||||||
unsigned long LogBuffer::getSize(log_id_t /*id*/) {
|
unsigned long LogBuffer::getSize(log_id_t /*id*/) {
|
||||||
return LOG_BUFFER_SIZE;
|
return log_buffer_size(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
log_time LogBuffer::flushTo(
|
log_time LogBuffer::flushTo(
|
||||||
SocketClient *reader, const log_time start, bool privileged,
|
SocketClient *reader, const log_time start, bool privileged,
|
||||||
bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
|
bool (*filter)(const LogBufferElement *element, void *arg), void *arg) {
|
||||||
|
|
@ -221,3 +375,24 @@ log_time LogBuffer::flushTo(
|
||||||
|
|
||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
|
||||||
|
log_time oldest(CLOCK_MONOTONIC);
|
||||||
|
|
||||||
|
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->getMonotonicTime();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stats.format(strp, uid, logMask, oldest);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mLogElementsLock);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "LogBufferElement.h"
|
#include "LogBufferElement.h"
|
||||||
#include "LogTimes.h"
|
#include "LogTimes.h"
|
||||||
|
#include "LogStatistics.h"
|
||||||
|
#include "LogWhiteBlackList.h"
|
||||||
|
|
||||||
typedef android::List<LogBufferElement *> LogBufferElementCollection;
|
typedef android::List<LogBufferElement *> LogBufferElementCollection;
|
||||||
|
|
||||||
|
|
@ -32,8 +34,13 @@ class LogBuffer {
|
||||||
LogBufferElementCollection mLogElements;
|
LogBufferElementCollection mLogElements;
|
||||||
pthread_mutex_t mLogElementsLock;
|
pthread_mutex_t mLogElementsLock;
|
||||||
|
|
||||||
unsigned long mSizes[LOG_ID_MAX];
|
LogStatistics stats;
|
||||||
unsigned long mElements[LOG_ID_MAX];
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
PruneList mPrune;
|
||||||
|
|
||||||
|
unsigned long mMaxSize[LOG_ID_MAX];
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LastLogTimes &mTimes;
|
LastLogTimes &mTimes;
|
||||||
|
|
@ -49,7 +56,18 @@ public:
|
||||||
|
|
||||||
void clear(log_id_t id);
|
void clear(log_id_t id);
|
||||||
unsigned long getSize(log_id_t id);
|
unsigned long getSize(log_id_t id);
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
int setSize(log_id_t id, unsigned long size);
|
||||||
|
#endif
|
||||||
unsigned long getSizeUsed(log_id_t id);
|
unsigned long getSizeUsed(log_id_t id);
|
||||||
|
// *strp uses malloc, use free to release.
|
||||||
|
void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
int initPrune(char *cp) { return mPrune.init(cp); }
|
||||||
|
// *strp uses malloc, use free to release.
|
||||||
|
void formatPrune(char **strp) { mPrune.format(strp); }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void maybePrune(log_id_t id);
|
void maybePrune(log_id_t id);
|
||||||
|
|
@ -57,4 +75,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // _LOGD_LOG_BUFFER_H__
|
||||||
|
|
|
||||||
555
logd/LogStatistics.cpp
Normal file
555
logd/LogStatistics.cpp
Normal file
|
|
@ -0,0 +1,555 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <log/logger.h>
|
||||||
|
#include <private/android_filesystem_config.h>
|
||||||
|
#include <utils/String8.h>
|
||||||
|
|
||||||
|
#include "LogStatistics.h"
|
||||||
|
|
||||||
|
PidStatistics::PidStatistics(pid_t pid)
|
||||||
|
: pid(pid)
|
||||||
|
, mSizesTotal(0)
|
||||||
|
, mElementsTotal(0)
|
||||||
|
, mSizes(0)
|
||||||
|
, mElements(0) { }
|
||||||
|
|
||||||
|
void PidStatistics::add(unsigned short size) {
|
||||||
|
mSizesTotal += size;
|
||||||
|
++mElementsTotal;
|
||||||
|
mSizes += size;
|
||||||
|
++mElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PidStatistics::subtract(unsigned short size) {
|
||||||
|
mSizes -= size;
|
||||||
|
--mElements;
|
||||||
|
return mElements == 0 && kill(pid, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PidStatistics::addTotal(size_t size, size_t element) {
|
||||||
|
if (pid == gone) {
|
||||||
|
mSizesTotal += size;
|
||||||
|
mElementsTotal += element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UidStatistics::UidStatistics(uid_t uid)
|
||||||
|
: uid(uid) {
|
||||||
|
Pids.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
UidStatistics::~UidStatistics() {
|
||||||
|
PidStatisticsCollection::iterator it;
|
||||||
|
for (it = begin(); it != end();) {
|
||||||
|
delete (*it);
|
||||||
|
it = Pids.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UidStatistics::add(unsigned short size, pid_t pid) {
|
||||||
|
PidStatistics *p;
|
||||||
|
PidStatisticsCollection::iterator last;
|
||||||
|
PidStatisticsCollection::iterator it;
|
||||||
|
for (last = it = begin(); it != end(); last = it, ++it) {
|
||||||
|
p = *it;
|
||||||
|
if (pid == p->getPid()) {
|
||||||
|
p->add(size);
|
||||||
|
// poor-man sort, bubble upwards if bigger than last
|
||||||
|
if ((last != it) && ((*last)->sizesTotal() < p->sizesTotal())) {
|
||||||
|
Pids.erase(it);
|
||||||
|
Pids.insert(last, p);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// poor-man sort, insert if bigger than last or last is the gone entry.
|
||||||
|
bool insert = (last != it)
|
||||||
|
&& ((p->getPid() == p->gone)
|
||||||
|
|| ((*last)->sizesTotal() < (size_t) size));
|
||||||
|
p = new PidStatistics(pid);
|
||||||
|
if (insert) {
|
||||||
|
Pids.insert(last, p);
|
||||||
|
} else {
|
||||||
|
Pids.push_back(p);
|
||||||
|
}
|
||||||
|
p->add(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UidStatistics::subtract(unsigned short size, pid_t pid) {
|
||||||
|
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;
|
||||||
|
Pids.erase(it);
|
||||||
|
it = end();
|
||||||
|
--it;
|
||||||
|
if (it == end()) {
|
||||||
|
p = new PidStatistics(p->gone);
|
||||||
|
Pids.push_back(p);
|
||||||
|
} else {
|
||||||
|
p = *it;
|
||||||
|
if (p->getPid() != p->gone) {
|
||||||
|
p = new PidStatistics(p->gone);
|
||||||
|
Pids.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p->addTotal(szsTotal, elsTotal);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UidStatistics::sizes(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->sizes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sizes;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UidStatistics::elements(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->elements();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
UidStatisticsCollection::iterator it;
|
||||||
|
for (it = begin(); it != end(); ++it) {
|
||||||
|
UidStatistics *u = *it;
|
||||||
|
if (uid == u->getUid()) {
|
||||||
|
u->subtract(size, pid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
: 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];
|
||||||
|
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];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
const unsigned short spaces_current = 13;
|
||||||
|
const unsigned short spaces_total = 19;
|
||||||
|
|
||||||
|
if (*buf) {
|
||||||
|
free(buf);
|
||||||
|
*buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
android::String8 string(" span -> size/num");
|
||||||
|
size_t oldLength;
|
||||||
|
short spaces = 2;
|
||||||
|
|
||||||
|
log_id_for_each(i) {
|
||||||
|
if (logMask & (1 << i)) {
|
||||||
|
oldLength = string.length();
|
||||||
|
string.appendFormat("%*s%s", spaces, "", android_log_id_to_name(i));
|
||||||
|
spaces += spaces_total + oldLength - string.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spaces = 1;
|
||||||
|
log_time t(CLOCK_MONOTONIC);
|
||||||
|
unsigned long long 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();
|
||||||
|
string.appendFormat("%*s%zu/%zu", spaces, "",
|
||||||
|
sizesTotal(i), elementsTotal(i));
|
||||||
|
spaces += spaces_total + oldLength - string.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
spaces = 1;
|
||||||
|
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);
|
||||||
|
|
||||||
|
log_id_for_each(i) {
|
||||||
|
if (!(logMask & (1 << i))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t els = elements(i);
|
||||||
|
if (els) {
|
||||||
|
oldLength = string.length();
|
||||||
|
string.appendFormat("%*s%zu/%zu", spaces, "", sizes(i), els);
|
||||||
|
spaces -= string.length() - oldLength;
|
||||||
|
}
|
||||||
|
spaces += spaces_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_id_for_each(i) {
|
||||||
|
if (!(logMask & (1 << i))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool 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) {
|
||||||
|
string.appendFormat("%*s", spaces, "");
|
||||||
|
}
|
||||||
|
spaces = 0;
|
||||||
|
|
||||||
|
uid_t u = up->getUid();
|
||||||
|
pid_t p = (*pt)->getPid();
|
||||||
|
|
||||||
|
intermediate = string.format(oneline
|
||||||
|
? ((p == PidStatistics::gone)
|
||||||
|
? "%d/?"
|
||||||
|
: "%d/%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) {
|
||||||
|
string.appendFormat("%*s=", spaces, "");
|
||||||
|
spaces = -1;
|
||||||
|
} else if (els) {
|
||||||
|
oldLength = string.length();
|
||||||
|
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) {
|
||||||
|
PidStatistics *pp = *pt;
|
||||||
|
pid_t 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 = kill(p, 0);
|
||||||
|
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) {
|
||||||
|
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) {
|
||||||
|
string.appendFormat("%*s=", spaces, "");
|
||||||
|
spaces = -1;
|
||||||
|
} else if (els) {
|
||||||
|
oldLength = string.length();
|
||||||
|
string.appendFormat("%*s%zu/%zu", spaces, "",
|
||||||
|
pp->sizes(), els);
|
||||||
|
spaces -= string.length() - oldLength;
|
||||||
|
}
|
||||||
|
spaces += spaces_current;
|
||||||
|
|
||||||
|
first = !first;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gone_els) {
|
||||||
|
if (!first && spaces) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
152
logd/LogStatistics.h
Normal file
152
logd/LogStatistics.h
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOGD_LOG_STATISTICS_H__
|
||||||
|
#define _LOGD_LOG_STATISTICS_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <log/log.h>
|
||||||
|
#include <log/log_read.h>
|
||||||
|
#include <utils/List.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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const pid_t gone = (pid_t) -1;
|
||||||
|
|
||||||
|
PidStatistics(pid_t pid);
|
||||||
|
|
||||||
|
pid_t getPid() const { return pid; }
|
||||||
|
|
||||||
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef android::List<PidStatistics *> PidStatisticsCollection;
|
||||||
|
|
||||||
|
class UidStatistics {
|
||||||
|
const uid_t uid;
|
||||||
|
|
||||||
|
PidStatisticsCollection Pids;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UidStatistics(uid_t uid);
|
||||||
|
~UidStatistics();
|
||||||
|
|
||||||
|
PidStatisticsCollection::iterator begin() { return Pids.begin(); }
|
||||||
|
PidStatisticsCollection::iterator end() { return Pids.end(); }
|
||||||
|
|
||||||
|
uid_t getUid() { return uid; }
|
||||||
|
|
||||||
|
void add(unsigned short size, pid_t pid);
|
||||||
|
void subtract(unsigned short size, pid_t pid);
|
||||||
|
|
||||||
|
static const pid_t pid_all = (pid_t) -1;
|
||||||
|
|
||||||
|
size_t sizes(pid_t pid = pid_all);
|
||||||
|
size_t elements(pid_t pid = pid_all);
|
||||||
|
|
||||||
|
size_t sizesTotal(pid_t pid = pid_all);
|
||||||
|
size_t elementsTotal(pid_t pid = pid_all);
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Log Statistics
|
||||||
|
class LogStatistics {
|
||||||
|
LidStatistics LogIds[LOG_ID_MAX];
|
||||||
|
|
||||||
|
size_t mSizes[LOG_ID_MAX];
|
||||||
|
size_t mElements[LOG_ID_MAX];
|
||||||
|
|
||||||
|
public:
|
||||||
|
const log_time start;
|
||||||
|
|
||||||
|
LogStatistics();
|
||||||
|
|
||||||
|
LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// *strp = malloc, balance with free
|
||||||
|
void format(char **strp, uid_t uid, unsigned int logMask, log_time oldest);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _LOGD_LOG_STATISTICS_H__
|
||||||
243
logd/LogWhiteBlackList.cpp
Normal file
243
logd/LogWhiteBlackList.cpp
Normal file
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USERDEBUG_BUILD
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <utils/String8.h>
|
||||||
|
|
||||||
|
#include "LogWhiteBlackList.h"
|
||||||
|
|
||||||
|
// White and Black list
|
||||||
|
|
||||||
|
Prune::Prune(uid_t uid, pid_t pid)
|
||||||
|
: mUid(uid)
|
||||||
|
, mPid(pid)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
int Prune::cmp(uid_t uid, pid_t pid) const {
|
||||||
|
if ((mUid == uid_all) || (mUid == uid)) {
|
||||||
|
if (mPid == pid_all) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pid - mPid;
|
||||||
|
}
|
||||||
|
return uid - mUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Prune::format(char **strp) {
|
||||||
|
if (mUid != uid_all) {
|
||||||
|
asprintf(strp, (mPid != pid_all) ? "%u/%u" : "%u", mUid, mPid);
|
||||||
|
} else {
|
||||||
|
// NB: mPid == pid_all can not happen if mUid == uid_all
|
||||||
|
asprintf(strp, (mPid != pid_all) ? "/%u" : "/", mPid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PruneList::PruneList()
|
||||||
|
: mWorstUidEnabled(true) {
|
||||||
|
mNaughty.clear();
|
||||||
|
mNice.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
PruneList::~PruneList() {
|
||||||
|
PruneCollection::iterator it;
|
||||||
|
for (it = mNice.begin(); it != mNice.end();) {
|
||||||
|
delete (*it);
|
||||||
|
it = mNice.erase(it);
|
||||||
|
}
|
||||||
|
for (it = mNaughty.begin(); it != mNaughty.end();) {
|
||||||
|
delete (*it);
|
||||||
|
it = mNaughty.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int PruneList::init(char *str) {
|
||||||
|
mWorstUidEnabled = true;
|
||||||
|
PruneCollection::iterator it;
|
||||||
|
for (it = mNice.begin(); it != mNice.end();) {
|
||||||
|
delete (*it);
|
||||||
|
it = mNice.erase(it);
|
||||||
|
}
|
||||||
|
for (it = mNaughty.begin(); it != mNaughty.end();) {
|
||||||
|
delete (*it);
|
||||||
|
it = mNaughty.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWorstUidEnabled = false;
|
||||||
|
|
||||||
|
for(; *str; ++str) {
|
||||||
|
if (isspace(*str)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PruneCollection *list;
|
||||||
|
if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented
|
||||||
|
++str;
|
||||||
|
// special case, translates to worst UID at priority in blacklist
|
||||||
|
if (*str == '!') {
|
||||||
|
mWorstUidEnabled = true;
|
||||||
|
++str;
|
||||||
|
if (!*str) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!isspace(*str)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!*str) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
list = &mNaughty;
|
||||||
|
} else {
|
||||||
|
list = &mNice;
|
||||||
|
}
|
||||||
|
|
||||||
|
uid_t uid = Prune::uid_all;
|
||||||
|
if (isdigit(*str)) {
|
||||||
|
uid = 0;
|
||||||
|
do {
|
||||||
|
uid = uid * 10 + *str++ - '0';
|
||||||
|
} while (isdigit(*str));
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t pid = Prune::pid_all;
|
||||||
|
if (*str == '/') {
|
||||||
|
++str;
|
||||||
|
if (isdigit(*str)) {
|
||||||
|
pid = 0;
|
||||||
|
do {
|
||||||
|
pid = pid * 10 + *str++ - '0';
|
||||||
|
} while (isdigit(*str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*str && !isspace(*str)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert sequentially into list
|
||||||
|
PruneCollection::iterator it = list->begin();
|
||||||
|
while (it != list->end()) {
|
||||||
|
Prune *p = *it;
|
||||||
|
int m = uid - p->mUid;
|
||||||
|
if (m == 0) {
|
||||||
|
if (p->mPid == p->pid_all) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
|
||||||
|
it = list->erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m = pid - p->mPid;
|
||||||
|
}
|
||||||
|
if (m >= 0) {
|
||||||
|
if (m > 0) {
|
||||||
|
list->insert(it, new Prune(uid,pid));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
if (it == list->end()) {
|
||||||
|
list->push_back(new Prune(uid,pid));
|
||||||
|
}
|
||||||
|
if (!*str) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PruneList::format(char **strp) {
|
||||||
|
if (*strp) {
|
||||||
|
free(*strp);
|
||||||
|
*strp = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char nice_format[] = " %s";
|
||||||
|
const char *fmt = nice_format + 1;
|
||||||
|
|
||||||
|
android::String8 string;
|
||||||
|
|
||||||
|
if (mWorstUidEnabled) {
|
||||||
|
string.setTo("~!");
|
||||||
|
fmt = nice_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
PruneCollection::iterator it;
|
||||||
|
|
||||||
|
for (it = mNice.begin(); it != mNice.end(); ++it) {
|
||||||
|
char *a = NULL;
|
||||||
|
(*it)->format(&a);
|
||||||
|
|
||||||
|
string.appendFormat(fmt, a);
|
||||||
|
fmt = nice_format;
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char naughty_format[] = " ~%s";
|
||||||
|
fmt = naughty_format + (*fmt != ' ');
|
||||||
|
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
|
||||||
|
char *a = NULL;
|
||||||
|
(*it)->format(&a);
|
||||||
|
|
||||||
|
string.appendFormat(fmt, a);
|
||||||
|
fmt = naughty_format;
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
*strp = strdup(string.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
|
||||||
|
// If there is scaling issues, resort to a better algorithm than linear
|
||||||
|
// based on these assumptions.
|
||||||
|
|
||||||
|
bool PruneList::naughty(LogBufferElement *element) {
|
||||||
|
PruneCollection::iterator it;
|
||||||
|
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
|
||||||
|
if (!(*it)->cmp(element)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PruneList::nice(LogBufferElement *element) {
|
||||||
|
PruneCollection::iterator it;
|
||||||
|
for (it = mNice.begin(); it != mNice.end(); ++it) {
|
||||||
|
if (!(*it)->cmp(element)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USERDEBUG_BUILD
|
||||||
71
logd/LogWhiteBlackList.h
Normal file
71
logd/LogWhiteBlackList.h
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LOGD_LOG_WHITE_BLACK_LIST_H__
|
||||||
|
#define _LOGD_LOG_WHITE_BLACK_LIST_H__
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <utils/List.h>
|
||||||
|
|
||||||
|
#include <LogBufferElement.h>
|
||||||
|
|
||||||
|
// White and Blacklist
|
||||||
|
|
||||||
|
class Prune {
|
||||||
|
friend class PruneList;
|
||||||
|
|
||||||
|
const uid_t mUid;
|
||||||
|
const pid_t mPid;
|
||||||
|
int cmp(uid_t uid, pid_t pid) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const uid_t uid_all = (uid_t) -1;
|
||||||
|
static const pid_t pid_all = (pid_t) -1;
|
||||||
|
|
||||||
|
Prune(uid_t uid, pid_t pid);
|
||||||
|
|
||||||
|
uid_t getUid() const { return mUid; }
|
||||||
|
pid_t getPid() const { return mPid; }
|
||||||
|
|
||||||
|
int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
|
||||||
|
|
||||||
|
// *strp is malloc'd, use free to release
|
||||||
|
void format(char **strp);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef android::List<Prune *> PruneCollection;
|
||||||
|
|
||||||
|
class PruneList {
|
||||||
|
PruneCollection mNaughty;
|
||||||
|
PruneCollection mNice;
|
||||||
|
bool mWorstUidEnabled;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PruneList();
|
||||||
|
~PruneList();
|
||||||
|
|
||||||
|
int init(char *str);
|
||||||
|
|
||||||
|
bool naughty(LogBufferElement *element);
|
||||||
|
bool nice(LogBufferElement *element);
|
||||||
|
bool worstUidEnabled() const { return mWorstUidEnabled; }
|
||||||
|
|
||||||
|
// *strp is malloc'd, use free to release
|
||||||
|
void format(char **strp);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
|
||||||
Loading…
Add table
Reference in a new issue