1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <ctype.h> 18 19 #include <android-base/stringprintf.h> 20 #include <cutils/properties.h> 21 22 #include "LogWhiteBlackList.h" 23 24 // White and Black list 25 26 Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) { 27 } 28 29 int Prune::cmp(uid_t uid, pid_t pid) const { 30 if ((mUid == uid_all) || (mUid == uid)) { 31 if (mPid == pid_all) { 32 return 0; 33 } 34 return pid - mPid; 35 } 36 return uid - mUid; 37 } 38 39 std::string Prune::format() { 40 if (mUid != uid_all) { 41 if (mPid != pid_all) { 42 return android::base::StringPrintf("%u/%u", mUid, mPid); 43 } 44 return android::base::StringPrintf("%u", mUid); 45 } 46 if (mPid != pid_all) { 47 return android::base::StringPrintf("/%u", mPid); 48 } 49 // NB: mPid == pid_all can not happen if mUid == uid_all 50 return std::string("/"); 51 } 52 53 PruneList::PruneList() { 54 init(NULL); 55 } 56 57 PruneList::~PruneList() { 58 PruneCollection::iterator it; 59 for (it = mNice.begin(); it != mNice.end();) { 60 it = mNice.erase(it); 61 } 62 for (it = mNaughty.begin(); it != mNaughty.end();) { 63 it = mNaughty.erase(it); 64 } 65 } 66 67 int PruneList::init(const char* str) { 68 mWorstUidEnabled = true; 69 mWorstPidOfSystemEnabled = true; 70 PruneCollection::iterator it; 71 for (it = mNice.begin(); it != mNice.end();) { 72 it = mNice.erase(it); 73 } 74 for (it = mNaughty.begin(); it != mNaughty.end();) { 75 it = mNaughty.erase(it); 76 } 77 78 static const char _default[] = "default"; 79 // default here means take ro.logd.filter, persist.logd.filter then 80 // internal default in that order. 81 if (str && !strcmp(str, _default)) { 82 str = NULL; 83 } 84 static const char _disable[] = "disable"; 85 if (str && !strcmp(str, _disable)) { 86 str = ""; 87 } 88 89 std::string filter; 90 91 if (str) { 92 filter = str; 93 } else { 94 char property[PROPERTY_VALUE_MAX]; 95 property_get("ro.logd.filter", property, _default); 96 filter = property; 97 property_get("persist.logd.filter", property, filter.c_str()); 98 // default here means take ro.logd.filter 99 if (strcmp(property, _default)) { 100 filter = property; 101 } 102 } 103 104 // default here means take internal default. 105 if (filter == _default) { 106 // See README.property for description of filter format 107 filter = "~! ~1000/!"; 108 } 109 if (filter == _disable) { 110 filter = ""; 111 } 112 113 mWorstUidEnabled = false; 114 mWorstPidOfSystemEnabled = false; 115 116 for (str = filter.c_str(); *str; ++str) { 117 if (isspace(*str)) { 118 continue; 119 } 120 121 PruneCollection* list; 122 if ((*str == '~') || (*str == '!')) { // ~ supported, ! undocumented 123 ++str; 124 // special case, translates to worst UID at priority in blacklist 125 if (*str == '!') { 126 mWorstUidEnabled = true; 127 ++str; 128 if (!*str) { 129 break; 130 } 131 if (!isspace(*str)) { 132 return 1; 133 } 134 continue; 135 } 136 // special case, translated to worst PID of System at priority 137 static const char worstPid[] = "1000/!"; 138 if (!strncmp(str, worstPid, sizeof(worstPid) - 1)) { 139 mWorstPidOfSystemEnabled = true; 140 str += sizeof(worstPid) - 1; 141 if (!*str) { 142 break; 143 } 144 if (!isspace(*str)) { 145 return 1; 146 } 147 continue; 148 } 149 if (!*str) { 150 return 1; 151 } 152 list = &mNaughty; 153 } else { 154 list = &mNice; 155 } 156 157 uid_t uid = Prune::uid_all; 158 if (isdigit(*str)) { 159 uid = 0; 160 do { 161 uid = uid * 10 + *str++ - '0'; 162 } while (isdigit(*str)); 163 } 164 165 pid_t pid = Prune::pid_all; 166 if (*str == '/') { 167 ++str; 168 if (isdigit(*str)) { 169 pid = 0; 170 do { 171 pid = pid * 10 + *str++ - '0'; 172 } while (isdigit(*str)); 173 } 174 } 175 176 if ((uid == Prune::uid_all) && (pid == Prune::pid_all)) { 177 return 1; 178 } 179 180 if (*str && !isspace(*str)) { 181 return 1; 182 } 183 184 // insert sequentially into list 185 PruneCollection::iterator it = list->begin(); 186 while (it != list->end()) { 187 Prune& p = *it; 188 int m = uid - p.mUid; 189 if (m == 0) { 190 if (p.mPid == p.pid_all) { 191 break; 192 } 193 if ((pid == p.pid_all) && (p.mPid != p.pid_all)) { 194 it = list->erase(it); 195 continue; 196 } 197 m = pid - p.mPid; 198 } 199 if (m <= 0) { 200 if (m < 0) { 201 list->insert(it, Prune(uid, pid)); 202 } 203 break; 204 } 205 ++it; 206 } 207 if (it == list->end()) { 208 list->push_back(Prune(uid, pid)); 209 } 210 if (!*str) { 211 break; 212 } 213 } 214 215 return 0; 216 } 217 218 std::string PruneList::format() { 219 static const char nice_format[] = " %s"; 220 const char* fmt = nice_format + 1; 221 222 std::string string; 223 224 if (mWorstUidEnabled) { 225 string = "~!"; 226 fmt = nice_format; 227 if (mWorstPidOfSystemEnabled) { 228 string += " ~1000/!"; 229 } 230 } 231 232 PruneCollection::iterator it; 233 234 for (it = mNice.begin(); it != mNice.end(); ++it) { 235 string += android::base::StringPrintf(fmt, (*it).format().c_str()); 236 fmt = nice_format; 237 } 238 239 static const char naughty_format[] = " ~%s"; 240 fmt = naughty_format + (*fmt != ' '); 241 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) { 242 string += android::base::StringPrintf(fmt, (*it).format().c_str()); 243 fmt = naughty_format; 244 } 245 246 return string; 247 } 248 249 // ToDo: Lists are in sorted order, Prune->cmp() returns + or - 250 // If there is scaling issues, resort to a better algorithm than linear 251 // based on these assumptions. 252 253 bool PruneList::naughty(LogBufferElement* element) { 254 PruneCollection::iterator it; 255 for (it = mNaughty.begin(); it != mNaughty.end(); ++it) { 256 if (!(*it).cmp(element)) { 257 return true; 258 } 259 } 260 return false; 261 } 262 263 bool PruneList::nice(LogBufferElement* element) { 264 PruneCollection::iterator it; 265 for (it = mNice.begin(); it != mNice.end(); ++it) { 266 if (!(*it).cmp(element)) { 267 return true; 268 } 269 } 270 return false; 271 } 272