| /* | |
| * 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(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); | |
| } | |
| 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 = nullptr; | |
| } | |
| 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; | |
| } |