blob: f739865a56bea14a9e5c008cfccdd6886accbc9d [file] [log] [blame]
/*
* 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 <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(false) {
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;
}