272 lines
7.2 KiB
C++
272 lines
7.2 KiB
C++
/*
|
|
* 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/stringprintf.h>
|
|
#include <cutils/properties.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;
|
|
}
|
|
|
|
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(NULL);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
static const char _default[] = "default";
|
|
// default here means take ro.logd.filter, persist.logd.filter then
|
|
// internal default in that order.
|
|
if (str && !strcmp(str, _default)) {
|
|
str = NULL;
|
|
}
|
|
static const char _disable[] = "disable";
|
|
if (str && !strcmp(str, _disable)) {
|
|
str = "";
|
|
}
|
|
|
|
std::string filter;
|
|
|
|
if (str) {
|
|
filter = str;
|
|
} else {
|
|
char property[PROPERTY_VALUE_MAX];
|
|
property_get("ro.logd.filter", property, _default);
|
|
filter = property;
|
|
property_get("persist.logd.filter", property, filter.c_str());
|
|
// default here means take ro.logd.filter
|
|
if (strcmp(property, _default)) {
|
|
filter = property;
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
}
|