Merge "logging: Use more inclusive language."
This commit is contained in:
commit
e72b290c8e
|
@ -333,14 +333,14 @@ Logd control:
|
|||
This can individually control each buffer's size with -b.
|
||||
-S, --statistics Output statistics.
|
||||
--pid can be used to provide pid specific stats.
|
||||
-p, --prune Print prune white and ~black list. Service is specified as UID,
|
||||
UID/PID or /PID. Weighed for quicker pruning if prefix with ~,
|
||||
otherwise weighed for longevity if unadorned. All other pruning
|
||||
activity is oldest first. Special case ~! represents an automatic
|
||||
quicker pruning for the noisiest UID as determined by the current
|
||||
statistics.
|
||||
-P, --prune='<list> ...' Set prune white and ~black list, using same format as listed above.
|
||||
Must be quoted.
|
||||
-p, --prune Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
|
||||
'~' prefix indicates that elements matching the rule should be pruned
|
||||
with higher priority otherwise they're pruned with lower priority. All
|
||||
other pruning activity is oldest first. Special case ~! represents an
|
||||
automatic pruning for the noisiest UID as determined by the current
|
||||
statistics. Special case ~1000/! represents pruning of the worst PID
|
||||
within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
|
||||
-P, --prune='<list> ...' Set prune rules, using same format as listed above. Must be quoted.
|
||||
|
||||
Filtering:
|
||||
-s Set default filter to silent. Equivalent to filterspec '*:S'
|
||||
|
|
|
@ -1301,7 +1301,7 @@ TEST(logcat, blocking_clear) {
|
|||
}
|
||||
#endif
|
||||
|
||||
static bool get_white_black(char** list) {
|
||||
static bool get_prune_rules(char** list) {
|
||||
FILE* fp = popen(logcat_executable " -p 2>/dev/null", "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
|
||||
|
@ -1334,7 +1334,7 @@ static bool get_white_black(char** list) {
|
|||
return *list != NULL;
|
||||
}
|
||||
|
||||
static bool set_white_black(const char* list) {
|
||||
static bool set_prune_rules(const char* list) {
|
||||
char buffer[BIG_BUFFER];
|
||||
snprintf(buffer, sizeof(buffer), logcat_executable " -P '%s' 2>&1",
|
||||
list ? list : "");
|
||||
|
@ -1363,28 +1363,28 @@ static bool set_white_black(const char* list) {
|
|||
return pclose(fp) == 0;
|
||||
}
|
||||
|
||||
TEST(logcat, white_black_adjust) {
|
||||
TEST(logcat, prune_rules_adjust) {
|
||||
char* list = NULL;
|
||||
char* adjust = NULL;
|
||||
|
||||
get_white_black(&list);
|
||||
get_prune_rules(&list);
|
||||
|
||||
static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
|
||||
ASSERT_EQ(true, set_white_black(adjustment));
|
||||
ASSERT_EQ(true, get_white_black(&adjust));
|
||||
ASSERT_EQ(true, set_prune_rules(adjustment));
|
||||
ASSERT_EQ(true, get_prune_rules(&adjust));
|
||||
EXPECT_STREQ(adjustment, adjust);
|
||||
free(adjust);
|
||||
adjust = NULL;
|
||||
|
||||
static const char adjustment2[] = "300/20 300/21 2000 ~1000";
|
||||
ASSERT_EQ(true, set_white_black(adjustment2));
|
||||
ASSERT_EQ(true, get_white_black(&adjust));
|
||||
ASSERT_EQ(true, set_prune_rules(adjustment2));
|
||||
ASSERT_EQ(true, get_prune_rules(&adjust));
|
||||
EXPECT_STREQ(adjustment2, adjust);
|
||||
free(adjust);
|
||||
adjust = NULL;
|
||||
|
||||
ASSERT_EQ(true, set_white_black(list));
|
||||
get_white_black(&adjust);
|
||||
ASSERT_EQ(true, set_prune_rules(list));
|
||||
get_prune_rules(&adjust);
|
||||
EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
|
||||
free(adjust);
|
||||
adjust = NULL;
|
||||
|
|
|
@ -58,8 +58,8 @@ cc_library_static {
|
|||
"LogReaderThread.cpp",
|
||||
"LogBufferElement.cpp",
|
||||
"LogStatistics.cpp",
|
||||
"LogWhiteBlackList.cpp",
|
||||
"LogTags.cpp",
|
||||
"PruneList.cpp",
|
||||
"SerializedFlushToState.cpp",
|
||||
"SerializedLogBuffer.cpp",
|
||||
"SerializedLogChunk.cpp",
|
||||
|
|
|
@ -298,33 +298,37 @@ class LogBufferElementLast {
|
|||
// invariably move the logs value down faster as less chatty sources would be
|
||||
// expired in the noise.
|
||||
//
|
||||
// The first loop performs blacklisting and worst offender pruning. Falling
|
||||
// through when there are no notable worst offenders and have not hit the
|
||||
// region lock preventing further worst offender pruning. This loop also looks
|
||||
// after managing the chatty log entries and merging to help provide
|
||||
// statistical basis for blame. The chatty entries are not a notification of
|
||||
// how much logs you may have, but instead represent how much logs you would
|
||||
// have had in a virtual log buffer that is extended to cover all the in-memory
|
||||
// logs without loss. They last much longer than the represented pruned logs
|
||||
// since they get multiplied by the gains in the non-chatty log sources.
|
||||
// The first pass prunes elements that match 3 possible rules:
|
||||
// 1) A high priority prune rule, for example ~100/20, which indicates elements from UID 100 and PID
|
||||
// 20 should be pruned in this first pass.
|
||||
// 2) The default chatty pruning rule, ~!. This rule sums the total size spent on log messages for
|
||||
// each UID this log buffer. If the highest sum consumes more than 12.5% of the log buffer, then
|
||||
// these elements from that UID are pruned.
|
||||
// 3) The default AID_SYSTEM pruning rule, ~1000/!. This rule is a special case to 2), if
|
||||
// AID_SYSTEM is the top consumer of the log buffer, then this rule sums the total size spent on
|
||||
// log messages for each PID in AID_SYSTEM in this log buffer and prunes elements from the PID
|
||||
// with the highest sum.
|
||||
// This pass reevaluates the sums for rules 2) and 3) for every log message pruned. It creates
|
||||
// 'chatty' entries for the elements that it prunes and merges related chatty entries together. It
|
||||
// completes when one of three conditions have been met:
|
||||
// 1) The requested element count has been pruned.
|
||||
// 2) There are no elements that match any of these rules.
|
||||
// 3) A reader is referencing the oldest element that would match these rules.
|
||||
//
|
||||
// The second loop get complicated because an algorithm of watermarks and
|
||||
// history is maintained to reduce the order and keep processing time
|
||||
// down to a minimum at scale. These algorithms can be costly in the face
|
||||
// of larger log buffers, or severly limited processing time granted to a
|
||||
// background task at lowest priority.
|
||||
// The second pass prunes elements starting from the beginning of the log. It skips elements that
|
||||
// match any low priority prune rules. It completes when one of three conditions have been met:
|
||||
// 1) The requested element count has been pruned.
|
||||
// 2) All elements except those mwatching low priority prune rules have been pruned.
|
||||
// 3) A reader is referencing the oldest element that would match these rules.
|
||||
//
|
||||
// This second loop does straight-up expiration from the end of the logs
|
||||
// (again, remember for the specified log buffer id) but does some whitelist
|
||||
// preservation. Thus whitelist is a Hail Mary low priority, blacklists and
|
||||
// spam filtration all take priority. This second loop also checks if a region
|
||||
// lock is causing us to buffer too much in the logs to help the reader(s),
|
||||
// and will tell the slowest reader thread to skip log entries, and if
|
||||
// persistent and hits a further threshold, kill the reader thread.
|
||||
//
|
||||
// The third thread is optional, and only gets hit if there was a whitelist
|
||||
// and more needs to be pruned against the backstop of the region lock.
|
||||
// The final pass only happens if there are any low priority prune rules and if the first two passes
|
||||
// were unable to prune the requested number of elements. It prunes elements all starting from the
|
||||
// beginning of the log, regardless of if they match any low priority prune rules.
|
||||
//
|
||||
// If the requested number of logs was unable to be pruned, KickReader() is called to mitigate the
|
||||
// situation before the next call to Prune() and the function returns false. Otherwise, if the
|
||||
// requested number of logs or all logs present in the buffer are pruned, in the case of Clear(),
|
||||
// it returns true.
|
||||
bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
|
||||
LogReaderThread* oldest = nullptr;
|
||||
bool clearAll = pruneRows == ULONG_MAX;
|
||||
|
@ -370,8 +374,8 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
return true;
|
||||
}
|
||||
|
||||
// prune by worst offenders; by blacklist, UID, and by PID of system UID
|
||||
bool hasBlacklist = (id != LOG_ID_SECURITY) && prune_->naughty();
|
||||
// First prune pass.
|
||||
bool check_high_priority = id != LOG_ID_SECURITY && prune_->HasHighPriorityPruneRules();
|
||||
while (!clearAll && (pruneRows > 0)) {
|
||||
// recalculate the worst offender on every batched pass
|
||||
int worst = -1; // not valid for uid() or getKey()
|
||||
|
@ -379,7 +383,7 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
size_t second_worst_sizes = 0;
|
||||
pid_t worstPid = 0; // POSIX guarantees PID != 0
|
||||
|
||||
if (worstUidEnabledForLogid(id) && prune_->worstUidEnabled()) {
|
||||
if (worstUidEnabledForLogid(id) && prune_->worst_uid_enabled()) {
|
||||
// Calculate threshold as 12.5% of available storage
|
||||
size_t threshold = max_size(id) / 8;
|
||||
|
||||
|
@ -389,14 +393,14 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
} else {
|
||||
stats()->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
|
||||
|
||||
if (worst == AID_SYSTEM && prune_->worstPidOfSystemEnabled()) {
|
||||
if (worst == AID_SYSTEM && prune_->worst_pid_of_system_enabled()) {
|
||||
stats()->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skip if we have neither worst nor naughty filters
|
||||
if ((worst == -1) && !hasBlacklist) {
|
||||
// skip if we have neither a worst UID or high priority prune rules
|
||||
if (worst == -1 && !check_high_priority) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -464,7 +468,7 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag()
|
||||
: element.uid();
|
||||
|
||||
if (hasBlacklist && prune_->naughty(&element)) {
|
||||
if (check_high_priority && prune_->IsHighPriority(&element)) {
|
||||
last.clear(&element);
|
||||
it = Erase(it);
|
||||
if (dropped) {
|
||||
|
@ -557,15 +561,17 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
}
|
||||
last.clear();
|
||||
|
||||
if (!kick || !prune_->worstUidEnabled()) {
|
||||
if (!kick || !prune_->worst_uid_enabled()) {
|
||||
break; // the following loop will ask bad clients to skip/drop
|
||||
}
|
||||
}
|
||||
|
||||
bool whitelist = false;
|
||||
bool hasWhitelist = (id != LOG_ID_SECURITY) && prune_->nice() && !clearAll;
|
||||
// Second prune pass.
|
||||
bool skipped_low_priority_prune = false;
|
||||
bool check_low_priority =
|
||||
id != LOG_ID_SECURITY && prune_->HasLowPriorityPruneRules() && !clearAll;
|
||||
it = GetOldest(id);
|
||||
while ((pruneRows > 0) && (it != logs().end())) {
|
||||
while (pruneRows > 0 && it != logs().end()) {
|
||||
LogBufferElement& element = *it;
|
||||
|
||||
if (element.log_id() != id) {
|
||||
|
@ -574,13 +580,12 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
}
|
||||
|
||||
if (oldest && oldest->start() <= element.sequence()) {
|
||||
if (!whitelist) KickReader(oldest, id, pruneRows);
|
||||
if (!skipped_low_priority_prune) KickReader(oldest, id, pruneRows);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasWhitelist && !element.dropped_count() && prune_->nice(&element)) {
|
||||
// WhiteListed
|
||||
whitelist = true;
|
||||
if (check_low_priority && !element.dropped_count() && prune_->IsLowPriority(&element)) {
|
||||
skipped_low_priority_prune = true;
|
||||
it++;
|
||||
continue;
|
||||
}
|
||||
|
@ -589,10 +594,10 @@ bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_u
|
|||
pruneRows--;
|
||||
}
|
||||
|
||||
// Do not save the whitelist if we are reader range limited
|
||||
if (whitelist && (pruneRows > 0)) {
|
||||
// Third prune pass.
|
||||
if (skipped_low_priority_prune && pruneRows > 0) {
|
||||
it = GetOldest(id);
|
||||
while ((it != logs().end()) && (pruneRows > 0)) {
|
||||
while (it != logs().end() && pruneRows > 0) {
|
||||
LogBufferElement& element = *it;
|
||||
|
||||
if (element.log_id() != id) {
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
#include "LogReaderThread.h"
|
||||
#include "LogStatistics.h"
|
||||
#include "LogTags.h"
|
||||
#include "LogWhiteBlackList.h"
|
||||
#include "LogWriter.h"
|
||||
#include "PruneList.h"
|
||||
#include "SimpleLogBuffer.h"
|
||||
#include "rwlock.h"
|
||||
|
||||
|
|
|
@ -215,15 +215,13 @@ int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli,
|
||||
int /*argc*/, char** /*argv*/) {
|
||||
int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli, int, char**) {
|
||||
setname();
|
||||
cli->sendMsg(PackageString(prune()->format()).c_str());
|
||||
cli->sendMsg(PackageString(prune()->Format()).c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
|
||||
char** argv) {
|
||||
int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc, char** argv) {
|
||||
setname();
|
||||
if (!clientHasLogCredentials(cli)) {
|
||||
cli->sendMsg("Permission Denied");
|
||||
|
@ -238,15 +236,12 @@ int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc,
|
|||
str += argv[i];
|
||||
}
|
||||
|
||||
int ret = prune()->init(str.c_str());
|
||||
|
||||
if (ret) {
|
||||
if (!prune()->Init(str.c_str())) {
|
||||
cli->sendMsg("Invalid");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cli->sendMsg("success");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -301,7 +296,7 @@ int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int /*argc*/,
|
|||
|
||||
LOG(INFO) << "logd reinit";
|
||||
buf()->Init();
|
||||
prune()->init(nullptr);
|
||||
prune()->Init(nullptr);
|
||||
|
||||
// This only works on userdebug and eng devices to re-read the
|
||||
// /data/misc/logd/event-log-tags file right after /data is mounted.
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#include "LogListener.h"
|
||||
#include "LogStatistics.h"
|
||||
#include "LogTags.h"
|
||||
#include "LogWhiteBlackList.h"
|
||||
#include "PruneList.h"
|
||||
|
||||
class CommandListener : public FrameworkListener {
|
||||
public:
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "LogReaderList.h"
|
||||
#include "LogStatistics.h"
|
||||
#include "LogTags.h"
|
||||
#include "LogWhiteBlackList.h"
|
||||
#include "PruneList.h"
|
||||
#include "SerializedLogBuffer.h"
|
||||
#include "SimpleLogBuffer.h"
|
||||
|
||||
|
|
|
@ -665,10 +665,9 @@ int LogKlog::log(const char* buf, ssize_t len) {
|
|||
((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
|
||||
// register names like x18 but not driver names like en0
|
||||
((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
|
||||
// blacklist
|
||||
// ignore
|
||||
((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
|
||||
((size == warningLen) &&
|
||||
!fastcmp<strncasecmp>(tag, warning, warningLen)) ||
|
||||
((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
|
||||
((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
|
||||
((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
|
||||
p = start;
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* 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 <ctype.h>
|
||||
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include "LogWhiteBlackList.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::string Prune::format() {
|
||||
if (mUid != uid_all) {
|
||||
if (mPid != pid_all) {
|
||||
return android::base::StringPrintf("%u/%u", mUid, mPid);
|
||||
}
|
||||
return android::base::StringPrintf("%u", mUid);
|
||||
}
|
||||
if (mPid != pid_all) {
|
||||
return android::base::StringPrintf("/%u", mPid);
|
||||
}
|
||||
// NB: mPid == pid_all can not happen if mUid == uid_all
|
||||
return std::string("/");
|
||||
}
|
||||
|
||||
PruneList::PruneList() {
|
||||
init(nullptr);
|
||||
}
|
||||
|
||||
PruneList::~PruneList() {
|
||||
PruneCollection::iterator it;
|
||||
for (it = mNice.begin(); it != mNice.end();) {
|
||||
it = mNice.erase(it);
|
||||
}
|
||||
for (it = mNaughty.begin(); it != mNaughty.end();) {
|
||||
it = mNaughty.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
int PruneList::init(const char* str) {
|
||||
mWorstUidEnabled = true;
|
||||
mWorstPidOfSystemEnabled = true;
|
||||
PruneCollection::iterator it;
|
||||
for (it = mNice.begin(); it != mNice.end();) {
|
||||
it = mNice.erase(it);
|
||||
}
|
||||
for (it = mNaughty.begin(); it != mNaughty.end();) {
|
||||
it = mNaughty.erase(it);
|
||||
}
|
||||
|
||||
// default here means take ro.logd.filter, persist.logd.filter then
|
||||
// internal default in that order.
|
||||
if (str && !strcmp(str, "default")) {
|
||||
str = nullptr;
|
||||
}
|
||||
if (str && !strcmp(str, "disable")) {
|
||||
str = "";
|
||||
}
|
||||
|
||||
std::string filter;
|
||||
|
||||
if (str) {
|
||||
filter = str;
|
||||
} else {
|
||||
filter = android::base::GetProperty("ro.logd.filter", "default");
|
||||
auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
|
||||
// default here means take ro.logd.filter
|
||||
if (persist_filter != "default") {
|
||||
filter = persist_filter;
|
||||
}
|
||||
}
|
||||
|
||||
// default here means take internal default.
|
||||
if (filter == "default") {
|
||||
// See README.property for description of filter format
|
||||
filter = "~! ~1000/!";
|
||||
}
|
||||
if (filter == "disable") {
|
||||
filter = "";
|
||||
}
|
||||
|
||||
mWorstUidEnabled = false;
|
||||
mWorstPidOfSystemEnabled = false;
|
||||
|
||||
for (str = filter.c_str(); *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;
|
||||
}
|
||||
// special case, translated to worst PID of System at priority
|
||||
static const char worstPid[] = "1000/!";
|
||||
if (!strncmp(str, worstPid, sizeof(worstPid) - 1)) {
|
||||
mWorstPidOfSystemEnabled = true;
|
||||
str += sizeof(worstPid) - 1;
|
||||
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, Prune(uid, pid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it == list->end()) {
|
||||
list->push_back(Prune(uid, pid));
|
||||
}
|
||||
if (!*str) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string PruneList::format() {
|
||||
static const char nice_format[] = " %s";
|
||||
const char* fmt = nice_format + 1;
|
||||
|
||||
std::string string;
|
||||
|
||||
if (mWorstUidEnabled) {
|
||||
string = "~!";
|
||||
fmt = nice_format;
|
||||
if (mWorstPidOfSystemEnabled) {
|
||||
string += " ~1000/!";
|
||||
}
|
||||
}
|
||||
|
||||
PruneCollection::iterator it;
|
||||
|
||||
for (it = mNice.begin(); it != mNice.end(); ++it) {
|
||||
string += android::base::StringPrintf(fmt, (*it).format().c_str());
|
||||
fmt = nice_format;
|
||||
}
|
||||
|
||||
static const char naughty_format[] = " ~%s";
|
||||
fmt = naughty_format + (*fmt != ' ');
|
||||
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
|
||||
string += android::base::StringPrintf(fmt, (*it).format().c_str());
|
||||
fmt = naughty_format;
|
||||
}
|
||||
|
||||
return 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;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
#include "LogBufferElement.h"
|
||||
|
||||
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->uid(), e->pid()); }
|
||||
|
||||
std::string format();
|
||||
};
|
||||
|
||||
typedef std::list<Prune> PruneCollection;
|
||||
|
||||
class PruneList {
|
||||
PruneCollection mNaughty;
|
||||
PruneCollection mNice;
|
||||
bool mWorstUidEnabled;
|
||||
bool mWorstPidOfSystemEnabled;
|
||||
|
||||
public:
|
||||
PruneList();
|
||||
~PruneList();
|
||||
|
||||
int init(const char* str);
|
||||
|
||||
bool naughty(LogBufferElement* element);
|
||||
bool naughty(void) {
|
||||
return !mNaughty.empty();
|
||||
}
|
||||
bool nice(LogBufferElement* element);
|
||||
bool nice(void) {
|
||||
return !mNice.empty();
|
||||
}
|
||||
bool worstUidEnabled() const {
|
||||
return mWorstUidEnabled;
|
||||
}
|
||||
bool worstPidOfSystemEnabled() const {
|
||||
return mWorstPidOfSystemEnabled;
|
||||
}
|
||||
|
||||
std::string format();
|
||||
};
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* 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 "PruneList.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/properties.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
||||
bool Prune::Matches(LogBufferElement* element) const {
|
||||
return (uid_ == UID_ALL || uid_ == element->uid()) &&
|
||||
(pid_ == PID_ALL || pid_ == element->pid());
|
||||
}
|
||||
|
||||
std::string Prune::Format() const {
|
||||
if (uid_ != UID_ALL) {
|
||||
if (pid_ != PID_ALL) {
|
||||
return android::base::StringPrintf("%u/%u", uid_, pid_);
|
||||
}
|
||||
return android::base::StringPrintf("%u", uid_);
|
||||
}
|
||||
if (pid_ != PID_ALL) {
|
||||
return android::base::StringPrintf("/%u", pid_);
|
||||
}
|
||||
// NB: pid_ == PID_ALL can not happen if uid_ == UID_ALL
|
||||
return std::string("/");
|
||||
}
|
||||
|
||||
PruneList::PruneList() {
|
||||
Init(nullptr);
|
||||
}
|
||||
|
||||
bool PruneList::Init(const char* str) {
|
||||
high_priority_prune_.clear();
|
||||
low_priority_prune_.clear();
|
||||
|
||||
// default here means take ro.logd.filter, persist.logd.filter then internal default in order.
|
||||
if (str && !strcmp(str, "default")) {
|
||||
str = nullptr;
|
||||
}
|
||||
if (str && !strcmp(str, "disable")) {
|
||||
str = "";
|
||||
}
|
||||
|
||||
std::string filter;
|
||||
|
||||
if (str) {
|
||||
filter = str;
|
||||
} else {
|
||||
filter = android::base::GetProperty("ro.logd.filter", "default");
|
||||
auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
|
||||
// default here means take ro.logd.filter
|
||||
if (persist_filter != "default") {
|
||||
filter = persist_filter;
|
||||
}
|
||||
}
|
||||
|
||||
// default here means take internal default.
|
||||
if (filter == "default") {
|
||||
filter = "~! ~1000/!";
|
||||
}
|
||||
if (filter == "disable") {
|
||||
filter = "";
|
||||
}
|
||||
|
||||
worst_uid_enabled_ = false;
|
||||
worst_pid_of_system_enabled_ = false;
|
||||
|
||||
for (str = filter.c_str(); *str; ++str) {
|
||||
if (isspace(*str)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::list<Prune>* list;
|
||||
if (*str == '~' || *str == '!') { // ~ supported, ! undocumented
|
||||
++str;
|
||||
// special case, prune the worst UID of those using at least 1/8th of the buffer.
|
||||
if (*str == '!') {
|
||||
worst_uid_enabled_ = true;
|
||||
++str;
|
||||
if (!*str) {
|
||||
break;
|
||||
}
|
||||
if (!isspace(*str)) {
|
||||
LOG(ERROR) << "Nothing expected after '~!', but found '" << str << "'";
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// special case, translated to worst PID of System at priority
|
||||
static const char WORST_SYSTEM_PID[] = "1000/!";
|
||||
if (!strncmp(str, WORST_SYSTEM_PID, sizeof(WORST_SYSTEM_PID) - 1)) {
|
||||
worst_pid_of_system_enabled_ = true;
|
||||
str += sizeof(WORST_SYSTEM_PID) - 1;
|
||||
if (!*str) {
|
||||
break;
|
||||
}
|
||||
if (!isspace(*str)) {
|
||||
LOG(ERROR) << "Nothing expected after '~1000/!', but found '" << str << "'";
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!*str) {
|
||||
LOG(ERROR) << "Expected UID or PID after '~', but found nothing";
|
||||
return false;
|
||||
}
|
||||
list = &high_priority_prune_;
|
||||
} else {
|
||||
list = &low_priority_prune_;
|
||||
}
|
||||
|
||||
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) {
|
||||
LOG(ERROR) << "Expected UID/PID combination, but found none";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (*str && !isspace(*str)) {
|
||||
LOG(ERROR) << "Nothing expected after UID/PID combination, but found '" << str << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
list->emplace_back(uid, pid);
|
||||
if (!*str) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string PruneList::Format() const {
|
||||
std::vector<std::string> prune_rules;
|
||||
|
||||
if (worst_uid_enabled_) {
|
||||
prune_rules.emplace_back("~!");
|
||||
}
|
||||
if (worst_pid_of_system_enabled_) {
|
||||
prune_rules.emplace_back("~1000/!");
|
||||
}
|
||||
for (const auto& rule : low_priority_prune_) {
|
||||
prune_rules.emplace_back(rule.Format());
|
||||
}
|
||||
for (const auto& rule : high_priority_prune_) {
|
||||
prune_rules.emplace_back("~" + rule.Format());
|
||||
}
|
||||
return android::base::Join(prune_rules, " ");
|
||||
}
|
||||
|
||||
bool PruneList::IsHighPriority(LogBufferElement* element) const {
|
||||
for (const auto& rule : high_priority_prune_) {
|
||||
if (rule.Matches(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PruneList::IsLowPriority(LogBufferElement* element) const {
|
||||
for (const auto& rule : low_priority_prune_) {
|
||||
if (rule.Matches(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <list>
|
||||
|
||||
#include "LogBufferElement.h"
|
||||
|
||||
class Prune {
|
||||
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_(uid), pid_(pid) {}
|
||||
|
||||
bool Matches(LogBufferElement* element) const;
|
||||
std::string Format() const;
|
||||
|
||||
uid_t uid() const { return uid_; }
|
||||
pid_t pid() const { return pid_; }
|
||||
|
||||
private:
|
||||
const uid_t uid_;
|
||||
const pid_t pid_;
|
||||
};
|
||||
|
||||
class PruneList {
|
||||
public:
|
||||
PruneList();
|
||||
|
||||
bool Init(const char* str);
|
||||
std::string Format() const;
|
||||
|
||||
bool IsHighPriority(LogBufferElement* element) const;
|
||||
bool IsLowPriority(LogBufferElement* element) const;
|
||||
|
||||
bool HasHighPriorityPruneRules() const { return !high_priority_prune_.empty(); }
|
||||
bool HasLowPriorityPruneRules() const { return !low_priority_prune_.empty(); }
|
||||
|
||||
bool worst_uid_enabled() const { return worst_uid_enabled_; }
|
||||
bool worst_pid_of_system_enabled() const { return worst_pid_of_system_enabled_; }
|
||||
|
||||
private:
|
||||
std::list<Prune> high_priority_prune_;
|
||||
std::list<Prune> low_priority_prune_;
|
||||
|
||||
bool worst_uid_enabled_;
|
||||
bool worst_pid_of_system_enabled_;
|
||||
};
|
|
@ -65,8 +65,8 @@ NB:
|
|||
- number - support multipliers (K or M) for convenience. Range is limited
|
||||
to between 64K and 256M for log buffer sizes. Individual log buffer ids
|
||||
such as main, system, ... override global default.
|
||||
- Pruning filter is of form of a space-separated list of [~][UID][/PID]
|
||||
references, where '~' prefix means to blacklist otherwise whitelist. For
|
||||
blacklisting, UID or PID may be a '!' to instead reference the chattiest
|
||||
client, with the restriction that the PID must be in the UID group 1000
|
||||
(system or AID_SYSTEM).
|
||||
- Pruning filter rules are specified as UID, UID/PID or /PID. A '~' prefix indicates that elements
|
||||
matching the rule should be pruned with higher priority otherwise they're pruned with lower
|
||||
priority. All other pruning activity is oldest first. Special case ~! represents an automatic
|
||||
pruning for the noisiest UID as determined by the current statistics. Special case ~1000/!
|
||||
represents pruning of the worst PID within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
|
||||
|
|
|
@ -97,7 +97,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|||
size_t data_left = size;
|
||||
const uint8_t** pdata = &data;
|
||||
|
||||
prune_list.init(nullptr);
|
||||
prune_list.Init(nullptr);
|
||||
// We want to get pruning code to get called.
|
||||
log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
|
||||
|
||||
|
|
Loading…
Reference in New Issue