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
Prune(uid_t uid,pid_t pid)26 Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
27 }
28
cmp(uid_t uid,pid_t pid) const29 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
format()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
PruneList()53 PruneList::PruneList() {
54 init(NULL);
55 }
56
~PruneList()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
init(const char * str)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
format()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
naughty(LogBufferElement * element)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
nice(LogBufferElement * element)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