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